Come passare l’output del comando come argomenti multipli a un altro comando

Voglio passare ogni output da un comando come argomento multiplo a un secondo comando, ad esempio:

grep "pattern" input 

ritorna:

 file1 file2 file3 

e voglio copiare queste uscite, ad esempio:

 cp file1 file1.bac cp file2 file2.bac cp file3 file3.bac 

Come posso farlo in una volta? Qualcosa di simile a:

 grep "pattern" input | cp $1 $1.bac 

Puoi usare xargs :

 grep 'pattern' input | xargs -I% cp "%" "%.bac" 

Puoi usare $() per interpolare l’output di un comando. Quindi, potresti usare kill -9 $(grep -hP '^\d+$' $(ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk '{ print $9 }')) se lo volessi.

Oltre alla buona risposta di Chris Jester-Young , direi che xargs è anche una buona soluzione per queste situazioni:

 grep ... `ls -lad ... | awk '{ print $9 }'` | xargs kill -9 

ce la farà. Tutti insieme:

 grep -hP '^\d+$' `ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk '{ print $9 }'` | xargs kill -9 

Per completezza, menzionerò anche la sostituzione del comando e spiegherò perché questo non è raccomandato:

 cp $(grep -l "pattern" input) directory/ 

La cp `grep -l "pattern" input` directory/ è approssimativamente equivalente, ma è obsoleta e ingombrante, non usarla.)

Questo fallirà se l’output di grep produce un nome di file che contiene spazi bianchi o un metacarattere di shell.

Naturalmente, va bene usare questo se si sa esattamente quali nomi di file possono produrre grep e si è verificato che nessuno di essi è problematico. Ma per uno script di produzione, non usare questo.

Ad ogni modo, per lo scenario dell’OP, in cui è necessario fare riferimento a ciascuna partita individualmente e aggiungere un’estensione, le xargs o le alternative di while read sono comunque superiori.

Nel peggiore dei casi (ovvero nomi di file problematici o non specificati), passare le corrispondenze a una subshell tramite xargs :

 grep -l "pattern" input | xargs -r sh -c 'for f; do cp "$f" "$f.bac"; done' _ 

… dove ovviamente la sceneggiatura all’interno del ciclo for potrebbe essere arbitrariamente complessa.

Nel caso ideale, il comando che si desidera eseguire è semplice (o versatile) e basta semplicemente passarlo a un elenco arbitrariamente lungo di nomi di file. Ad esempio, GNU cp ha un’opzione -t per facilitare questo uso di xargs (l’opzione -t ti permette di mettere la directory di destinazione prima sulla riga di comando, così puoi mettere quanti file vuoi alla fine del comando ):

 grep -l "pattern" input | xargs cp -t destdir 

che si espanderà in

 cp -t destdir file1 file2 file3 file4 ... 

per quante corrispondenze come xargs possono adattare alla riga di comando di cp , ripetute tante volte quante sono necessarie per passare tutti i file a cp . (Purtroppo, questo non corrisponde allo scenario dell’OP: se è necessario rinominare tutti i file durante la copia, è necessario passare solo due argomenti per invocazione cp : il nome del file di origine e il nome del file di destinazione per copiarlo.)

Quindi, in altre parole, se si utilizza la syntax di sostituzione di comando e grep produce un elenco di corrispondenze molto lungo, si rischia di imbattersi in ARG_MAX e “Argument list too long”; ma xargs lo eviterà in modo specifico copiando solo il numero di argomenti che può tranquillamente passare a cp alla volta, ed eseguendo cp più volte, se necessario, invece.