
xargs son fuegos artificiales para comandos de shell. Cualquier salida, generada por cualquier comando de shell, puede enviarse a xargs para su posterior procesamiento en otra línea de comando. ¡Aprenda a aprovechar este gran poder de los xargs hoy mismo!
Introducción a xargs
Mi colega Dave McKay escribió un artículo interesante Cómo usar el comando xargs en Linux, que es posible que desee leer primero para obtener una introducción detallada y una exploración de los xargs en general.
Este artículo se centrará en un problema específico: qué hacer cuando encuentre limitaciones del apilamiento normal o basado en tuberías tradicionales (;
delimitado) apilamiento de comandos de Linux, e incluso cuando se usa xargs no parece dar una respuesta de inmediato?
Esto sucede con regularidad, si no con frecuencia, al escribir scripts de una línea en la línea de comando y / o al procesar datos complejos o estructuras de datos. La información que se presenta aquí se basa en investigaciones y muchos años de experiencia utilizando este método y enfoque en particular.
Tubos y xarg
Cualquiera que aprenda Bash crecerá en sus habilidades de scripting de línea de comandos con el tiempo. Lo mejor de Bash es que todas las habilidades aprendidas desde la línea de comandos se traducen fácilmente en scripts de Bash (que generalmente están marcados con un .sh
sufijo). La sintaxis es tan buena como idéntica.
Y, a medida que mejoran las habilidades, los nuevos ingenieros suelen descubrir primero el lenguaje Pipe. Usar una manguera es fácil y sencillo: la salida del comando anterior se 'canaliza' a la entrada para el siguiente comando Piense en ello como una tubería de agua que lleva agua desde una fuente de salida a una fuente de entrada en otro lugar, como ejemplo el agua de una presa conectada a una turbina de agua.
Echemos un vistazo a un ejemplo sencillo:
echo 'a' | sed 's/a/b/'
Aquí simplemente repetimos "a" y luego cambiamos lo mismo usando el editor de flujo de texto es. La salida es, por supuesto, "b": el sed reemplazó (comando s) "a" con "b".
Algún tiempo después, el ingeniero se dará cuenta de que los tubos todavía tienen capacidades limitadas, especialmente cuando desea preprocesar los datos en un formato listo para el siguiente instrumento. Por ejemplo, considere esta situación:
Aquí comenzamos un sueño de fondo. A continuación usamos pidof
para recuperar el PID del comando de suspensión en ejecución e intentar eliminarlo con kill -9
(Piense en -9 como una forma destructiva de matar un proceso). Falla. Así que intentamos usar el PID proporcionado por el shell cuando iniciamos el proceso en segundo plano, pero de manera similar falla.
El problema es ese kill
no acepta la entrada directamente, independientemente de si proviene de ps
o incluso de un simple echo
. Para resolver este problema, podemos usar xargs para obtener la salida de ambos archivos ps
o el echo
comando) y proporcionarlos como entrada kill
, convirtiéndolos en argumentos para el comando kill. Por tanto, es como si hubiéramos ejecutado kill -9 some_pid
directamente. Vamos a ver cómo funciona:
sleep 300 & pidof sleep | xargs kill -9
Funciona perfectamente y consigue lo que nos propusimos: acabar con el proceso de sueño. Un pequeño cambio en el código (es decir, simplemente agregue xargs delante del comando), ¡pero un gran cambio en la utilidad Bash para el ingeniero desarrollador!
También podemos utilizar el -I
opción (que define el argumento de cadena sustituto) a kill
para aclarar un poco la forma en que pasamos los argumentos para matar: i12b Aquí definimos {}
como nuestra cadena de reemplazo. En otras palabras, siempre que xargs vea {}
, reemplazará {}
a cualquier entrada recibida por el último comando.
Sin embargo, esto también tiene sus limitaciones. ¿Qué pasaría si quisiéramos proporcionar información de depuración agradable impresa en línea y desde la instrucción? Hasta ahora parece imposible.
Sí, podríamos procesar posteriormente la salida con un archivo sed
regex o inserte una subcapa ($()
) en algún lugar, pero todos estos todavía parecen tener limitaciones, especialmente cuando llega el momento de crear flujos de datos complejos, sin usar un nuevo comando y sin usar archivos temporales intermedios.
¿Y si pudiéramos, de una vez por todas, dejar atrás estos límites y ser 100% libres de crear lo que sea ¿Nos gusta la línea de comandos de Bash, usando solo tuberías, xargs y el shell Bash, sin archivos temporales intermedios y sin iniciar un nuevo comando? Es posible.
Y no es nada complejo si alguien te lo muestra, pero la primera vez tomó algo de tiempo y discusión para resolverlo. En particular, me gustaría agradecer y agradecer a mi mentor y colega anterior de Linux, Andrew Dalgleish: juntos descubrimos cómo hacerlo mejor hace poco menos de 10 años.
Bienvenido a xargs con bash -c
Como hemos visto, incluso cuando se utilizan tuberías junto con xargs, todavía existen limitaciones para la creación de scripts en el nivel de ingeniero senior. Tomemos nuestro ejemplo anterior y agreguemos información de depuración sin procesar el resultado. Normalmente esto sería difícil de lograr, pero no así con xargs
combinado con bash -c
:
sleep 300 & pidof sleep | xargs -I{} echo "echo 'The PID of your sleep process was: {}'; kill -9 {}; echo 'PID {} has now been terminated'" | xargs -I{} bash -c "{}"
Aquí hemos usado dos xargs
comandos. El primero crea una línea de comando personalizada, utilizando la salida del comando anterior en la tubería como entrada (siendo pidof sleep
) y el segundo comando xargs ejecuta ese comando generado, personalizado para la entrada (¡importante!).
¿Por qué personalizar por entrada? La razón es que xargs, por defecto, procesará línea por línea a través de su entrada (la salida del comando anterior en la tubería) y hará lo que se le ordene para cada una de esas líneas de entrada.
Aquí hay mucho poder. Esto significa que puede crear y compilar cualquier comando personalizado y luego ejecutarlo, completamente libre del formato en el que se encuentran sus datos de entrada y completamente libre de preocuparse por cómo ejecutarlo. La única sintaxis que debe recordar es esta:
some_command | xargs -I{} echo "echo '...{}...'; more_commands; more_commands_with_or_without{}" | xargs -I{} bash -c "{}"
Tenga en cuenta que el archivo anidado echo
(el segundo eco) solo es realmente necesario si desea reproducir el texto real. De lo contrario, si el último echo
el primero no estaba echo
comenzaría a producir "El PID ...", etc. y el archivo bash -c
el subshell no podría analizarlo como un comando (IOW, 'El PID ...' no es un comando y no se puede ejecutar como tal, de ahí el eco secundario / anidado).
Una vez que recuerdes el bash -c
, la -I{}
y la forma de hacer eco desde dentro de otro eco (y alternativamente podría usar secuencias de escape si es necesario), se encontrará usando esta sintaxis una y otra vez.
Digamos que necesita hacer tres cosas por archivo en el directorio: 1) ver el contenido del archivo, 2) moverlo a un subdirectorio, 3) eliminarlo. Normalmente, esto requeriría una serie de pasos con varios comandos escalonados, y si se vuelve más complejo, es posible que también necesite archivos temporales. Pero es muy facil de usar bash -c
es xargs
:
echo '1' > a echo '2' > b echo '3' > c mkdir subdir ls --color=never | grep -v subdir | xargs -I{} echo "cat {}; mv {} subdir; rm subdir/{}" | xargs -I{} bash -c "{}"
Primero, notar rápidamente que siempre es una buena idea usar --color=never
para ls
, para evitar problemas en el sistema usando codificación de colores para las salidas de la lista de directorios (habilitado de manera predeterminada en Ubuntu), ya que esto a menudo causa graves problemas de análisis debido a los códigos de color que realmente se envían al terminal y se prefieren a las entradas lista de directorios.
Primero creamos tres archivos, a, byc y un subdirectorio llamado subdir. Excluimos este subdirectorio de la lista de directorios con grep -v
después de notar que se ejecuta una prueba rápida (sin ejecutar los comandos, o en otras palabras, sin el segundo xarg), el subdirectorio aún se muestra.
Siempre es importante probar los comandos complejos primero mirando la salida antes de pasarlos a una subcapa de bash con bash -c
para la ejecución.
Finalmente, usamos exactamente el mismo método visto arriba para compilar o ordenar; cat
(mostrar) el archivo, mover el archivo (indicado por {}
) en el subdirectorio y finalmente elimine el archivo dentro del subdirectorio. Vemos que el contenido de los 3 archivos (1, 2, 3) se muestra en la pantalla y si revisamos el directorio actual nuestros archivos se han ido. También podemos ver cómo no hay más archivos en el subdirectorio. Todo funcionó bien.
Terminando
Utilizando xargs
ser un gran poder para un usuario avanzado de Linux (y en este caso) Bash. Utilizando xargs
en combinación con bash -c
todavía trae un poder mucho mayor; la capacidad única de crear líneas de comando 100% complejas y personalizadas, sin la necesidad de archivos intermedios o construcciones, y sin la necesidad de comandos apilados / secuenciados.
¡Disfrutar!
Deja una respuesta