Una funzione di shell. Funzionerà in qualsiasi shell che supporti <<<
stringhe-qui, incluse zsh e bash.
xyz() {
while read line
do
printf "%s " "$line"
"[email protected]" <<<"$line"
done
}
$ (echo "foo"; echo "bar") | xyz rev
foo oof
bar rab
Ci saranno molti problemi nella maggior parte dei casi a causa del modo in cui funziona il buffering stdio. Una soluzione per Linux potrebbe essere quella di utilizzare stdbuf
programmare ed eseguire il comando con coproc, in modo da poter controllare esplicitamente l'interleaving dell'output.
Quanto segue presuppone che il comando genererà una riga dopo ogni riga di input.
#!/bin/bash
coproc stdbuf -i0 -o0 "[email protected]"
IFS=
while read -r in ; do
printf "%s " "$in"
printf "%s\n" "$in" >&${COPROC[1]}
read -r out <&${COPROC[0]}
printf "%s\n" "$out"
done
Se è necessaria una soluzione più generale poiché l'OP richiedeva solo che ogni riga di input al programma alla fine emette una riga anziché immediatamente, è necessario un approccio più complicato. Crea un ciclo di eventi utilizzando read -t 0
per provare a leggere da stdin e dal co-processo, se hai lo stesso "numero di riga" per entrambi allora emetti, altrimenti memorizza la riga. Per evitare di utilizzare il 100% della cpu se in qualsiasi round del ciclo di eventi nessuno dei due era pronto, introdurre un piccolo ritardo prima di eseguire nuovamente il ciclo di eventi. Ci sono ulteriori complicazioni se il processo emette righe parziali, queste devono essere bufferizzate.
Se è necessaria questa soluzione più generale, la scriverei utilizzando wait poiché ha già un buon supporto per la gestione della corrispondenza dei modelli su più flussi di input. Tuttavia questa non è una soluzione bash/zsh.
In questo caso particolare, userei perl
:
printf '%s\n' foo bar | perl -Mopen=locale -lpe '$_ .= " " . reverse$_'
foo oof
bar rab
Che potresti estendere per lavorare anche con cluster di grafema:
$ printf '%s\n' $'complique\u301' |
perl -Mopen=locale -lpe '$_ .= " " . join "", reverse/\X/g'
compliqué éuqilpmoc
Oppure zsh
:
while IFS= read -r line; do
print -r -- $line ${(j::)${(s::Oa)line}}
done
Anche se eviterei di usare while read
loop per elaborare il testo, anche in zsh
(anche se in questo caso particolare non è poi così male visto che vengono usati solo comandi interni).
Nel caso generale, l'utilizzo di file temporanei è probabilmente l'approccio migliore. Con zsh
, puoi farlo con:
(){paste -d ' ' $1 <(rev <$1)} =(print -l foo bar)
(dove =(...)
si occupa di creare e ripulire il file temporaneo).
Sostituendolo con tubi e qualche forma di tee
ing è una ricetta per lo stallo nel caso generale. Vedi queste domande simili per alcuni approcci e dettagli sulle situazioni di deadlock:
- Dividi un input per comando diverso e combina il risultato
- tee + cat:usa un output più volte e poi concatena i risultati