Esiste un modo per leggere le righe dall'output del comando?


8

Ho un comando pre-processo per l'output di un file

./preprocess.sh > preprocessed_file 

e il preprocessed_filesarà usato in questo modo

while read line
do

    ./research.sh $line &

done < preprocessed_file 

rm -f preprocessed_file

Esiste un modo per indirizzare l'output sulla while read lineparte invece di inviarlo al file preprocessed? Penso che ci dovrebbe essere un modo migliore oltre all'utilizzo di questa temperatura preprocessed_file.

Risposte:


8

È possibile utilizzare la sostituzione del processo bash :

while IFS= read -r line; do
  ./research.sh "$line" &
done < <(./preprocess.sh)

Alcuni vantaggi della sostituzione di processo:

  • Non è necessario salvare file temporanei.
  • Prestazioni migliori. Leggere da un altro processo spesso più velocemente della scrittura su disco, quindi rileggere.
  • Risparmia tempo per il calcolo da quando viene eseguito contemporaneamente con l'espansione di parametri e variabili, la sostituzione dei comandi e l'espansione aritmetica

cosa significano le doppie frecce a sinistra (<<)?
Marcus Thornton,

@MarcusThornton: <è un reindirizzamento, mentre <(...)è la sintassi di sostituzione del processo. Dovresti leggere: gnu.org/software/bash/manual/html_node/… per maggiori dettagli.
cuonglm

Fatto. <(...)fa parte della sintassi.
Marcus Thornton,

2
Non è necessariamente più veloce. Perché quando si legge da una pipe readdeve leggere un byte alla volta, mentre può ottimizzare le cose con la lettura di blocchi più grandi e cercare all'indietro quando si legge da un file normale. La cosa migliore è evitare del while readtutto i loop, in primo luogo quando possibile. Si noti inoltre che è necessario IFS= read -r lineleggere la riga in $line. E lasciare qui $linenon quotato (invocando l'operatore split + glob) probabilmente non ha senso.
Stéphane Chazelas,

1
@mikeserv, comanda spesso il buffer di linea (al contrario del buffer completo) il loro output quando va su un terminale. Qui sto dicendo che l' readintegrato della shell legge un carattere alla volta quando legge da una pipe (indipendentemente da ciò che si trova all'altra estremità della pipe che readnon ha modo di sapere), che è una delle ragioni per cui i while readloop sono tremendamente lenti.
Stéphane Chazelas,

15

Sì! È possibile utilizzare una pipe di processo |.

./preprocess.sh |
    while IFS= read -r line
    do
        ./research.sh "$line" &
    done

Una pipe di processo passa l'output standard ( stdout) di un processo all'input standard ( stdin) di quello successivo.

Se lo si desidera, è possibile inserire un carattere di nuova riga dopo a |ed estendere il comando alla riga successiva.

Nota: a|bè equivalente b < <(a), ma senza i file magici, e in un ordine più leggibile, soprattutto quando la pipeline si allunga.

a|b|c è equivalente a c < <(b < <(a))

e

a|b|c|d|e è e < < (d < <(c < <(b < <(a))))


3
Nota: questa soluzione con il pipe ha il vantaggio di essere più portatile della sostituzione del processo (non supportata da alcune shell POSIX come il trattino). Sempre per quanto riguarda la portabilità, il lato destro di una pipe può essere eseguito in una subshell (questo dipende dalla shell), in modo che eventuali effetti collaterali (come l'impostazione delle variabili) non possano influenzare l'ambiente dello script della shell.
vinc17,

In genere è più sicuro inserire riferimenti variabili come $linetra virgolette doppie (ad esempio, nel tuo script ./research.sh "$line" &).
G-Man dice "Ripristina Monica" il

1
@ G-Man Forse non in questo contesto. Se research.shfunziona con l'array dell'argomento della riga di comando ed $lineè, ad esempio, "uno due", con l'intenzione che il primo argomento sia "uno" e il secondo argomento "due", la citazione $linerenderà impossibile - invece il primo argomento sarà "uno due" e non ce ne sarà un secondo ...
goldilocks

2
" a|bequivale ab < <(a) " - vicino, ma non del tutto. Nella versione pipe, entrambi i lati della pipe vengono eseguiti in subshell, mentre nella versione di sostituzione processo, solo il processo sostituito viene eseguito in una subshell, ma aviene eseguito nell'ambito del livello di shell attualmente in esecuzione. Ciò ha importanti implicazioni per la portata delle variabili impostate all'internoa
Trauma digitale il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.