Para completar, también mencionaré la sustitución de comandos y explicaré por qué esto no se recomienda:
cp $(grep -l "pattern" input) directory/
(La sintaxis de acento grave cp `grep -l "pattern" input` directory/
es más o menos equivalente, pero es obsoleto y difícil de manejar; no uses eso.)
Esto fallará si la salida de grep
produce un nombre de archivo que contiene espacios en blanco o un metacarácter de shell.
Por supuesto, está bien usar esto si sabe exactamente qué archivo nombra el grep
puede producir, y he comprobado que ninguno de ellos es problemático. Pero para un guión de producción, no use esto.
De todos modos, para el escenario del OP, donde debe referirse a cada coincidencia individualmente y agregarle una extensión, el xargs
o while read
las alternativas son superiores de todos modos.
En el peor de los casos (es decir, nombres de archivo problemáticos o no especificados), pase las coincidencias a una subcapa a través de xargs
:
grep -l "pattern" input |
xargs -r sh -c 'for f; do cp "$f" "$f.bac"; done' _
... donde obviamente el script dentro del for
bucle podría ser arbitrariamente complejo.
En el caso ideal, el comando que desea ejecutar es lo suficientemente simple (o versátil) como para que simplemente pueda pasarle una lista arbitrariamente larga de nombres de archivo. Por ejemplo, GNU cp
tiene un -t
opción para facilitar este uso de xargs
(el -t
le permite poner el directorio de destino primero en la línea de comando, para que pueda poner tantos archivos como desee al final del comando):
grep -l "pattern" input | xargs cp -t destdir
que se expandirá en
cp -t destdir file1 file2 file3 file4 ...
para tantas coincidencias como xargs
puede caber en la línea de comando de cp
, repetido tantas veces como sea necesario para pasar todos los archivos a cp
. (Desafortunadamente, esto no coincide con el escenario del OP; si necesita cambiar el nombre de cada archivo mientras copia, debe pasar solo dos argumentos por cp
invocación:el nombre del archivo de origen y el nombre del archivo de destino para copiarlo.)
En otras palabras, si usa la sintaxis de sustitución de comandos y grep
produce un realmente larga lista de coincidencias, corre el riesgo de toparse con ARG_MAX
y errores de "Lista de argumentos demasiado larga"; pero xargs
evitará específicamente esto copiando en su lugar solo tantos argumentos como pueda pasar con seguridad a cp
a la vez y ejecutando cp
varias veces si es necesario.
Puedes usar xargs
:
grep 'pattern' input | xargs -I% cp "%" "%.bac"
Puedes usar $()
para interpolar la salida de un comando. Entonces, podrías usar kill -9 $(grep -hP '^\d+$' $(ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk '{ print $9 }'))
si quisieras.
Además de la buena respuesta de Chris Jester-Young, diría que xargs
también es una buena solución para estas situaciones:
grep ... `ls -lad ... | awk '{ print $9 }'` | xargs kill -9
lo hará Todos juntos:
grep -hP '^\d+$' `ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk '{ print $9 }'` | xargs kill -9