xargs
è la soluzione più flessibile per suddividere l'output in argomenti di comando.
È anche molto leggibile e facile da usare grazie alla sua semplice parametrizzazione.
Il formato è xargs -n $NUMLINES mycommand
.
Ad esempio, a echo
ogni singola riga in un file /tmp/tmp.txt
faresti:
cat /tmp/tmp.txt | xargs -n 1 echo
O a diff
ogni coppia successiva di file elencati come righe in un file con il nome sopra che faresti:
cat /tmp/tmp.txt | xargs -n 2 diff
Il -n 2
istruisce xargs
consumare e passare come argomenti separati due righe alla volta di ciò che ci hai inviato.
Puoi personalizzare xargs
per dividere sui delimitatori oltre a ritorno a capo/nuova riga.
Usa man xargs
e google per saperne di più sulla potenza di questa versatile utility.
Il modo migliore per farlo è reindirizzare il file nel ciclo:
# Basic idea. Keep reading for improvements.
FILE=test
while read CMD; do
echo "$CMD"
done < "$FILE"
Un reindirizzamento con < "$FILE"
ha alcuni vantaggi rispetto a cat "$FILE" | while ...
. Evita un uso inutile di cat, salvando un processo figlio non necessario. Evita anche una trappola comune in cui il ciclo viene eseguito in una subshell. In Bash, comandi in un |
la pipeline viene eseguita in subshell, il che significa che le assegnazioni delle variabili vengono perse al termine del ciclo. Reindirizzamento con <
non ha quel problema, quindi potresti usare $CMD
dopo il ciclo o modificare altre variabili all'interno del ciclo. Inoltre, ancora una volta, evita processi figlio non necessari.
Ci sono alcuni miglioramenti aggiuntivi che potrebbero essere apportati:
- Aggiungi
IFS=
in modo cheread
non taglierà gli spazi bianchi iniziali e finali da ogni riga. - Aggiungi
-r
aread
per evitare che le barre rovesciate vengano interpretate come sequenze di escape. CMD
minuscolo eFILE
. La convenzione di Bash è che solo le variabili ambientali e interne della shell sono maiuscole.- Usa
printf
al posto diecho
che è più sicuro se$cmd
è una stringa come-n
, cheecho
interpreterebbe come una bandiera.
file=test
while IFS= read -r cmd; do
printf '%s\n' "$cmd"
done < "$file"
Quello che hai è convogliare il testo "cat test"
nel ciclo.
Vuoi solo:
cat test | \
while read CMD; do
echo $CMD
done