Pasar la salida de un comando como argumentos con xargs

última modificación:

La tubería (|) conecta la salida de un comando con la entrada del siguiente. Pero muchos comandos no leen de la entrada estándar (stdin): esperan argumentos. rm, grep, chmod o wc no hacen nada útil si les envías datos por la entrada estándar (necesitan que les pases los archivos como argumentos).

xargs resuelve eso: lee líneas de la entrada estándar y las convierte en argumentos para el comando que le indiques.

echo -e "uno\ndos\ntres" | xargs echo

Resultado: uno dos tres. Las tres líneas se pasan como tres argumentos a echo.

El caso más habitual es combinarlo con find:

find . -name "*.log" | xargs grep "error"

find devuelve una lista de archivos, uno por línea. xargs los convierte en argumentos de grep. El resultado es equivalente a grep "error" archivo1.log archivo2.log ... pero sin tener que escribir los nombres a mano.

Lo mismo para borrar:

find . -name "*.tmp" | xargs rm

Sin xargs, find . -name "*.tmp" | rm no funciona porque rm no lee de la entrada estándar.

Cuando necesitas controlar dónde va el argumento dentro del comando (no solo al final), usa -I{}:

find . -name "*.log" | xargs -I{} mv {} {}.bak

{} es el marcador de posición. Aquí xargs ejecuta un mv por cada archivo, renombrándolo con la extensión .bak.

Con -n controlas cuántos argumentos pasa en cada ejecución:

find . -name "*.log" | xargs -n1 gzip

Ejecuta gzip una vez por archivo en lugar de pasarlos todos de golpe.

Con -P se pueden ejecutar varios procesos en paralelo. Útil cuando hay muchos archivos y el comando tarda:

find . -name "*.log" | xargs -P4 -n1 gzip

Lanza hasta 4 procesos gzip simultáneos en lugar de uno tras otro.

xargs también resuelve un problema práctico: la consola tiene un límite en la longitud de la línea de comandos. Si tienes miles de archivos, rm *.log puede fallar con “argument list too long”. xargs los procesa en lotes y el error desaparece.