xargs es particularmente útil cuando tienes una lista de rutas de archivos en stdin y quieres hacer algo con ellas. Por ejemplo:
$ git ls-files "*.tex" | xargs -n 1 sed -i "s/color/colour/g"
Examinemos esto paso a paso:
$ git ls-files "*.tex"
tex/ch1/intro.tex
tex/ch1/motivation.tex
....
En otras palabras, nuestra entrada es una lista de caminos en los que queremos hacer algo.
Para saber qué hace xargs con estas rutas, un buen truco es agregar echo
antes de su comando, así:
$ git ls-files "*.tex" | xargs -n 1 echo sed -i "s/color/colour/g"
sed -i "s/color/colour/g" tex/ch1/intro.tex
sed -i "s/color/colour/g" tex/ch1/motivation.tex
....
El -n 1
argumento hará que xargs convierta cada línea en un comando propio. El sed -i "s/color/colour/g"
comando reemplazará todas las apariciones de color
con colour
para el archivo especificado.
Tenga en cuenta que esto solo funciona si no tiene espacios en sus caminos. Si lo hace, debe usar rutas terminadas nulas como entrada a xargs pasando la -0
bandera. Un ejemplo de uso sería:
$ git ls-files -z "*.tex" | xargs -0 -n 1 sed -i "s/color/colour/g"
Lo que hace lo mismo que describimos anteriormente, pero también funciona si uno de los caminos tiene un espacio.
Esto funciona con cualquier comando que produce nombres de archivo como salida como find
o locate
. Sin embargo, si lo usa en un repositorio de git con muchos archivos, podría ser más eficiente usarlo en git grep -l
lugar de git ls-files
, de esta manera:
$ git grep -l "color" "*.tex" | xargs -n 1 sed -i "s/color/colour/g"
El git grep -l "color" "*.tex"
comando dará una lista de archivos "* .tex" que contienen la frase "color".
xargs
y$(...)
), xargs es mucho más seguro que la sustitución de comandos. Y no recuerdo haber encontrado un nombre de archivo legítimo con una nueva línea. ¿No son los problemas de escape y expansión de palabras problemas con la sustitución de comandos, no xargs?