Pour être complet, je mentionnerai également la substitution de commande et expliquerai pourquoi cela n'est pas recommandé :
cp $(grep -l "pattern" input) directory/
(La syntaxe backtick cp `grep -l "pattern" input` directory/
est à peu près équivalent, mais il est obsolète et peu maniable ; ne l'utilisez pas.)
Cela échouera si la sortie de grep
produit un nom de fichier qui contient des espaces blancs ou un métacaractère shell.
Bien sûr, c'est bien de l'utiliser si vous savez exactement quel fichier nomme le grep
peut produire, et avoir vérifié qu'aucun d'entre eux n'est problématique. Mais pour un script de production, n'utilisez pas ceci.
Quoi qu'il en soit, pour le scénario de l'OP, où vous devez vous référer à chaque match individuellement et y ajouter une extension, le xargs
ou while read
les alternatives sont supérieures de toute façon.
Dans le pire des cas (c'est-à-dire des noms de fichiers problématiques ou non spécifiés), passez les correspondances à un sous-shell via xargs
:
grep -l "pattern" input |
xargs -r sh -c 'for f; do cp "$f" "$f.bac"; done' _
... où évidemment le script à l'intérieur du for
boucle pourrait être arbitrairement complexe.
Dans le cas idéal, la commande que vous souhaitez exécuter est suffisamment simple (ou polyvalente) pour que vous puissiez simplement lui transmettre une liste arbitrairement longue de noms de fichiers. Par exemple, GNU cp
a un -t
option pour faciliter cette utilisation de xargs
(le -t
L'option vous permet de placer le répertoire de destination en premier sur la ligne de commande, vous pouvez donc mettre autant de fichiers que vous le souhaitez à la fin de la commande) :
grep -l "pattern" input | xargs cp -t destdir
qui s'étendra dans
cp -t destdir file1 file2 file3 file4 ...
pour autant de correspondances que xargs
peut tenir sur la ligne de commande de cp
, répété autant de fois qu'il le faut pour passer tous les fichiers à cp
. (Malheureusement, cela ne correspond pas au scénario de l'OP ; si vous devez renommer chaque fichier lors de la copie, vous devez transmettre seulement deux arguments par cp
invocation :le nom du fichier source et le nom du fichier de destination dans lequel le copier.)
Donc, en d'autres termes, si vous utilisez la syntaxe de substitution de commande et grep
produit un vraiment longue liste de correspondances, vous risquez de tomber sur ARG_MAX
et les erreurs "Liste d'arguments trop longue" ; mais xargs
évitera spécifiquement cela en copiant à la place autant d'arguments qu'il peut passer en toute sécurité à cp
à la fois, et exécutant cp
plusieurs fois si nécessaire à la place.
Vous pouvez utiliser xargs
:
grep 'pattern' input | xargs -I% cp "%" "%.bac"
Vous pouvez utiliser $()
pour interpoler la sortie d'une commande. Donc, vous pouvez utiliser kill -9 $(grep -hP '^\d+$' $(ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk '{ print $9 }'))
si vous le vouliez.
En plus de la bonne réponse de Chris Jester-Young, je dirais que xargs
est également une bonne solution pour ces situations :
grep ... `ls -lad ... | awk '{ print $9 }'` | xargs kill -9
le fera. Tous ensemble :
grep -hP '^\d+$' `ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk '{ print $9 }'` | xargs kill -9