Per completezza, citerò anche la sostituzione dei comandi e spiegherò perché non è consigliata:
cp $(grep -l "pattern" input) directory/
(La sintassi del backtick cp `grep -l "pattern" input` directory/
è più o meno equivalente, ma è obsoleto e ingombrante; non usarlo.)
Questo fallirà se l'output da grep
produce un nome di file che contiene spazi bianchi o un metacarattere della shell.
Naturalmente, va bene usare questo se sai esattamente quale file nomina il grep
possono produrre e hanno 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 corrispondenza individualmente e aggiungere un'estensione ad essa, il xargs
o while read
le alternative sono comunque superiori.
Nel caso peggiore (ovvero nomi di file problematici o non specificati), passa 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 lo script all'interno del for
loop potrebbe essere arbitrariamente complesso.
Nel caso ideale, il comando che vuoi eseguire è abbastanza semplice (o versatile) da potergli semplicemente passare un elenco arbitrariamente lungo di nomi di file. Ad esempio, GNU cp
ha un -t
opzione per facilitare questo uso di xargs
(il -t
L'opzione consente di inserire la directory di destinazione prima sulla riga di comando, quindi puoi inserire tutti i file che 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 un numero di corrispondenze pari a xargs
può entrare nella riga di comando di cp
, ripetuto tante volte quante sono necessarie per passare tutti i file a cp
. (Sfortunatamente, questo non corrisponde allo scenario dell'OP; se devi rinominare ogni file durante la copia, devi passare solo due argomenti per cp
invocazione:il nome del file di origine e il nome del file di destinazione in cui copiarlo.)
Quindi, in altre parole, se usi la sintassi di sostituzione dei comandi e grep
produce un davvero lungo elenco di corrispondenze, rischi di imbatterti in ARG_MAX
ed errori "Elenco argomenti troppo lungo"; ma xargs
lo eviterà specificatamente copiando invece solo il numero di argomenti che può tranquillamente passare a cp
alla volta ed eseguendo cp
più volte se necessario invece.
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