linux shell unix

linux - Cómo pasar la salida del comando como argumentos múltiples a otro comando



shell unix (4)

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 haremos. Todos juntos:

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

Quiero pasar cada salida de un comando como argumento múltiple a un segundo comando, por ejemplo:

grep "pattern" input

devoluciones:

file1 file2 file3

y quiero copiar estos resultados, por ejemplo:

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

¿Cómo puedo hacer eso de una vez? Algo como:

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


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 backtick cp `grep -l "pattern" input` directory/ es más o menos equivalente, pero es obsoleta y difícil de manejar; no la use).

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é nombres de archivo puede producir el grep , y ha verificado 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, los xargs o las alternativas de while read 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 subshell 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 ciclo for podría ser arbitrariamente complejo.

En el caso ideal, el comando que desea ejecutar es lo suficientemente simple (o versátil) como para simplemente pasarle una lista arbitrariamente larga de nombres de archivo. Por ejemplo, GNU cp tiene una opción -t para facilitar este uso de xargs (la opción -t permite colocar el directorio de destino primero en la línea de comando, para que pueda colocar 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 puedan caber en la línea de comando de cp , repite 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 durante la copia, debe pasar solo dos argumentos por invocación cp : 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 una lista realmente larga de coincidencias, corre el riesgo de toparse con los ARG_MAX y "Lista de argumentos demasiado larga"; pero xargs evitará esto específicamente copiando solo tantos argumentos como pueda pasar de manera segura a cp a la vez y ejecutando cp varias veces si es necesario.


Puede usar $() para interpolar la salida de un comando. Entonces, podría usar kill -9 $(grep -hP ''^/d+$'' $(ls -lad /dir/*/pid | grep -P ''/dir//d+/pid'' | awk ''{ print $9 }'')) si quisieras.


Puedes usar xargs :

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