Me parece que todas las respuestas existentes en esta página son incorrectas, incluida la marcada como correcta. Eso se debe al hecho de que la pregunta está formulada de manera ambigua.
Resumen: si desea ejecutar el comando "exactamente una vez para cada línea de entrada dada", pasando toda la línea (sin la nueva línea) al comando como un argumento único, entonces esta es la mejor manera compatible con UNIX para hacerlo:
... | tr '\n' '\0' | xargs -0 -n1 ...
GNU xargs
puede o no tener extensiones útiles que le permitan eliminar tr
, pero no están disponibles en OS X y otros sistemas UNIX.
Ahora para la larga explicación ...
Hay dos problemas a tener en cuenta al usar xargs:
- ¿Cómo divide la entrada en "argumentos"? y
- cuántos argumentos para pasar el comando hijo a la vez.
Para probar el comportamiento de xargs, necesitamos una utilidad que muestre cuántas veces se está ejecutando y con cuántos argumentos. No sé si hay una utilidad estándar para hacer eso, pero podemos codificarla con bastante facilidad en bash:
#!/bin/bash
echo -n "-> "; for a in "$@"; do echo -n "\"$a\" "; done; echo
Suponiendo que lo guarde como show
en su directorio actual y lo haga ejecutable, así es como funciona:
$ ./show one two 'three and four'
-> "one" "two" "three and four"
Ahora, si la pregunta original es realmente sobre el punto 2 anterior (como creo que es, después de leerlo varias veces) y debe leerse así (cambia en negrita):
¿Cómo puedo hacer que xargs ejecute el comando exactamente una vez para cada argumento de entrada dado? Su comportamiento predeterminado es dividir la entrada en argumentos y ejecutar el comando las menos veces posible , pasando múltiples argumentos a cada instancia.
entonces la respuesta es -n 1
.
Comparemos el comportamiento predeterminado de xargs, que divide la entrada en espacios en blanco y llama al comando las menos veces posible:
$ echo one two 'three and four' | xargs ./show
-> "one" "two" "three" "and" "four"
y su comportamiento con -n 1
:
$ echo one two 'three and four' | xargs -n 1 ./show
-> "one"
-> "two"
-> "three"
-> "and"
-> "four"
Si, por otro lado, la pregunta original era sobre el punto 1. división de entrada y debía leerse así (muchas personas que vienen aquí parecen pensar que ese es el caso, o están confundiendo los dos problemas):
¿Cómo puedo hacer que xargs ejecute el comando con exactamente un argumento para cada línea de entrada dada? Su comportamiento predeterminado es dividir las líneas alrededor del espacio en blanco .
entonces la respuesta es más sutil.
Uno podría pensar que -L 1
podría ser de ayuda, pero resulta que no cambia el análisis de argumentos. Solo ejecuta el comando una vez para cada línea de entrada, con tantos argumentos como había en esa línea de entrada:
$ echo $'one\ntwo\nthree and four' | xargs -L 1 ./show
-> "one"
-> "two"
-> "three" "and" "four"
No solo eso, sino que si una línea termina con espacios en blanco, se agrega a la siguiente:
$ echo $'one \ntwo\nthree and four' | xargs -L 1 ./show
-> "one" "two"
-> "three" "and" "four"
Claramente, -L
no se trata de cambiar la forma en que xargs divide la entrada en argumentos.
El único argumento que lo hace de una manera multiplataforma (excluyendo las extensiones GNU) es -0
, que divide la entrada alrededor de bytes NUL.
Entonces, solo es cuestión de traducir nuevas líneas a NUL con la ayuda de tr
:
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 ./show
-> "one " "two" "three and four"
Ahora el análisis del argumento se ve bien, incluido el espacio en blanco al final.
Finalmente, si combina esta técnica con -n 1
, obtendrá exactamente una ejecución de comando por línea de entrada, cualquiera que sea la entrada que tenga, que puede ser otra forma de ver la pregunta original (posiblemente la más intuitiva, dado el título):
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 -n1 ./show
-> "one "
-> "two"
-> "three and four"
find /path -type f -delete
sería aún más eficiente :)