xargs es uno de los comandos más poderosos de Linux. En este tutorial, le mostraré cómo puede xargs para convertir la entrada estándar en comandos.
¿Qué es el comando xargs?
El comando xargs lee líneas de texto de la entrada estándar o de la salida de otro comando y las convierte en comandos y los ejecuta.
A menudo encontrará que el comando xargs se usa con el comando de búsqueda. El comando de búsqueda le brinda una lista de nombres de archivo y el comando xargs le permite usar esos nombres de archivo, uno por uno, como si se hubieran ingresado en el otro comando.
Dado que xargs funciona en la redirección, recomiendo encarecidamente repasar sus conocimientos de stdin, stdout y redirección de tuberías en Linux.
¿Cómo usar el comando xargs?
El comando xargs tiene la siguiente sintaxis:
xargs [options] [command [initial-arguments]]
Pero probablemente no lo vayas a usar así. Su poder radica en combinar la salida de un comando con otro. Veámoslo con un ejemplo sencillo.
En mi directorio actual, tengo algunos archivos de texto y el archivo flowers.txt tiene el nombre de todos estos archivos:
[email protected]:~/tutorial$ ls
flowers.txt lily.txt one_lotus.txt rose.txt three_lotus.txt two_lotus.txt
[email protected]:~/tutorial$ cat flowers.txt
lily.txt
one_lotus.txt
rose.txt
three_lotus.txt
two_lotus.txt
Ahora mi objetivo es que quiero ver el tamaño de archivo de todos los archivos mencionados en el archivo flowers.txt. El sentido común dice que podría combinar el comando cat para mostrar todos los nombres de archivo y luego canalizarlo al comando du para verificar el tamaño del archivo.
Pero si lo canalizo directamente, no dará el tamaño de cada uno de los archivos mencionados en el archivo flowers.txt.
[email protected]:~/tutorial$ du -h
52K .
[email protected]:~/tutorial$ cat flowers.txt | du -h
52K .
¿Por qué? Primero, el comando du no toma entrada estándar. En segundo lugar, la salida del comando cat no son nombres de archivos individuales. Es como una palabra separada por un carácter de nueva línea.
La magia del comando xargs es que tomará esto y el texto separados por espacios en blanco o líneas nuevas y los convertirá en entradas individuales para el siguiente comando.
[email protected]:~/tutorial$ cat flowers.txt | xargs du -h
4.0K lily.txt
4.0K one_lotus.txt
16K rose.txt
4.0K three_lotus.txt
16K two_lotus.txt
Piense en ello como equivalente a enviar esos nombres de archivo al comando du:
[email protected]:~/tutorial$ du -h lily.txt one_lotus.txt rose.txt three_lotus.txt two_lotus.txt
4.0K lily.txt
4.0K one_lotus.txt
16K rose.txt
4.0K three_lotus.txt
16K two_lotus.txt
Te das cuenta del poder del comando xargs ahora, ¿no?
xargs y find:hechos el uno para el otro
A menudo encontrará que se usa en combinación con el "comando de búsqueda". El comando find busca archivos y directorios y devuelve sus nombres. Gracias a xargs, puede usar el resultado del comando de búsqueda para fines específicos, como renombrarlos, moverlos, eliminarlos y otras cosas.
Digamos que desea obtener todos los archivos que terminan en .txt y que contienen la palabra rojo. Puede combinar los comandos find y grep con la ayuda de xargs:
[email protected]:~/tutorial$ find . -type f -name "*.txt" | xargs grep -l red
./three_lotus.txt
./two_lotus.txt
./rose.txt
Tratar con nombres de archivo con espacios
Si tiene un archivo con espacio en su nombre, causará problemas. Digamos que cambié el nombre de three_lotus.txt a "tres lotus.txt". Ahora, cuando se procesa a través de xargs, se ve como dos archivos separados como tres y lotus.txt.
[email protected]:~/tutorial$ find . -type f -name "*.txt" | xargs grep -l red
./two_lotus.txt
grep: ./three: No such file or directory
grep: lotus.txt: No such file or directory
./rose.txt
En tales casos, debe usar la opción -print0 del comando de búsqueda. Separa líneas con caracteres nulos ASCII en lugar de caracteres de nueva línea. De manera similar, también debe usar xargs con -0 para aceptar los valores nulos ASCII.
[email protected]:~/tutorial$ find . -type f -print0 -name "*.txt" | xargs -0 grep -l red
./two_lotus.txt
./three lotus.txt
./rose.txt
Vea qué comando se está ejecutando
Si desea ver qué comando se está ejecutando con la ayuda de xargs, puede usar la opción -t. Imprimirá el comando real que se está ejecutando.
[email protected]:~/tutorial$ find . -type f -name "*.txt" | xargs -t touch
touch ./three_lotus.txt ./two_lotus.txt ./lily.txt ./rose.txt
Obligar a xargs a solicitar confirmación antes de ejecutar el comando
Algunas situaciones exigen tener mucho cuidado, como eliminar archivos. Será una buena idea ver qué comando se va a ejecutar y tener la opción de denegar la ejecución.
Puede usar la opción -p de xargs para obtener el aviso.
[email protected]:~/tutorial$ find . -type f -name "*.txt" | xargs -p rm
rm ./three_lotus.txt ./two_lotus.txt ./lily.txt ./rose.txt ?...n
Usando placeholder con xargs para tener más control
De forma predeterminada, el comando xargs agrega la entrada estándar como argumento al final del comando. Esto crea un problema cuando necesita usar eso antes del último argumento.
Por ejemplo, si usa el comando mover, primero necesita el origen y luego el destino. Si desea mover los archivos encontrados a un directorio de destino, este comando no funcionará:
[email protected]:~/tutorial$ find . -type f -name "*.txt" | xargs -p mv new_dir
mv new_dir ./three_lotus.txt ./two_lotus.txt ./lily.txt ./rose.txt ?...y
mv: target './rose.txt' is not a directory
Aquí es donde puede usar marcadores de posición en xargs con la opción -Me gusta esto:
[email protected]:~/tutorial$ find . -type f -name "*.txt" | xargs -p -I {} mv {} new_dir
mv ./three_lotus.txt new_dir ?...n
mv ./two_lotus.txt new_dir ?...n
mv ./lily.txt new_dir ?...n
mv ./rose.txt new_dir ?...n
Piense en ello como si xargs obtuviera todos los nombres de archivo del comando de búsqueda y lo mantuviera en {}. Luego va al comando mv y proporciona el contenido de {}.
La principal diferencia aquí es que en lugar de poner todos los nombres de archivo en el mismo comando, los agrega uno por uno. Esta es la razón por la que se ha llamado al comando mv para cada argumento (como puede ver en el ejemplo anterior).
Nota:Usé {} como marcador de posición. Puede usar la mayoría de las otras letras o caracteres como marcador de posición. {} es una apuesta segura y fácil de entender y distinguir.
Ejecutar múltiples comandos con xargs
Puede usar los marcadores de posición para ejecutar varios comandos con xargs.
[email protected]:~/tutorial$ find . -type f -name "*.txt" | xargs -I {} sh -c 'ls -l {}; du -h {}'
-rw-rw-r-- 1 abhishek abhishek 0 May 28 17:02 ./three_lotus.txt
0 ./three_lotus.txt
-rw-rw-r-- 1 abhishek abhishek 0 May 28 17:02 ./two_lotus.txt
0 ./two_lotus.txt
-rw-rw-r-- 1 abhishek abhishek 0 May 28 17:02 ./lily.txt
0 ./lily.txt
-rw-rw-r-- 1 abhishek abhishek 0 May 28 17:02 ./rose.txt
0 ./rose.txt
Tenga en cuenta que el marcador de posición no se extenderá a la siguiente redirección de tubería u otro comando. Es por eso que usé el comando sh aquí.
Siempre hay más...
He usado principalmente el comando find con xargs en los ejemplos aquí porque eso es lo que verá más. Pero eso no significa que xargs esté restringido para usarse solo con el comando de búsqueda. Uno de esos ejemplos prácticos del comando xargs es cuando desea detener todos los contenedores acoplables en ejecución:
docker ps -q | xargs docker stop
Como la mayoría de los otros comandos de Linux, también hay muchas más opciones con xargs. Siempre puede consultar la página de manual del comando xargs para obtener más información.
Creo que los ejemplos de comandos xargs enumerados aquí son suficientes para brindarle una buena comprensión de este increíble comando.
Si tiene alguna pregunta o sugerencia, hágamelo saber en la sección de comentarios.