Pasar múltiples parámetros a través de xargs


17

Me gustaría poder usar xargspara ejecutar múltiples parámetros en diferentes partes de un comando.

Por ejemplo, lo siguiente:

echo {1..8} | xargs -n2 | xargs -I v1 -I v2 echo the number v1 comes before v2

Espero que regrese

the number 1 comes before 2
the number 3 comes before 4 

... etc.

¿Es esto posible? Sospecho que mi uso múltiple de -Ies incorrecto.

Respuestas:


29

Creo que no puedes usarlo de -Iesa manera. Pero puede obtener el efecto / comportamiento que desea diciendo:

echo {1..8} | xargs -n2 sh -c 'echo "the number $1 comes before $2"' sh

Esto, esencialmente, crea un script de shell de una línea ad hoc , que se xargsejecuta a través de sh -c. Los dos valores que se xargsanalizan fuera de la entrada se pasan a este "script". El shell luego asigna esos valores a $1y $2, a los que luego puede hacer referencia en el "script".


44
Gracias, eso es genial. Sin embargo, he estado leyendo al hombre para sh y me cuesta entender qué hace la segunda llamada a sh y, por extensión, por qué su omisión produce 'la mitad' del resultado.
Damien Sawyer

66
@DamienSawyer No hay una segunda llamada a sh. El final shal final es lo que se pone $0. $0suele ser lo que contiene el nombre del intérprete o el guión.
Kusalananda

Acabo de reemplazar el seguimiento shcon el echo $shque funciona. Así que las shfunciones finales como marcador de posición
Kenn

Bueno, eso es una simplificación excesiva de lo que dijo Kusalananda.
Scott

6

En el caso específico de printf, siempre puedes hacer:

echo {1..8} | xargs printf 'the number %s comes before %s\n'

porque printftiene una xargscapacidad intrínseca de ejecutarse varias veces si se le dan más argumentos de los que necesita para una sola invocación. Aunque eso tiene poca ventaja sobre

printf 'the number %s comes before %s\n' {1..8}

Y para listas grandes, el xargscomando simple podría resultar en la xargsejecución de varias instancias printf, algunas de las cuales podrían tener un número impar de argumentos. Podría pasar -n 1000para xargsprotegerse de eso, donde 1000 es un número par que debería ser lo suficientemente pequeño como para no alcanzar el límite de la lista arg demasiado largo y lo suficientemente grande como para evitar ejecutar tantos printfs.

Tenga en cuenta que xargsllamaría, no a la construcción de su shell printf, sino a la externa printf, con cada invocación en un nuevo proceso separado.

También tenga en cuenta que para una entrada vacía, excepto en algunos BSD, todavía se ejecutaría printfuna vez sin argumento. GNU xargsy compatible tienen una -r (o --no-run-if-empty) opción para evitar eso.

Para ser claros, esta respuesta simple es específica para su printfejemplo, y no funcionaría en el caso general en el que debe pasar dos parámetros a la vez a su comando (como sería el caso diff, por ejemplo). Para resolver el problema general con zsh, puede usar:

for i j ({1..8}) echo "the number $i comes before $j"

(1) En mi humilde opinión, la zshparte de lo anterior es una respuesta real, y la parte xargssin opciones es simplemente una rareza. En tal caso, consideraría poner primero la respuesta real. (2) Supongo que tiene una razón para no usar comillas en su zshcomando. Si es así, puede indicarlo, para que la gente no lea lo anterior y empiece a pensar que las citas no son importantes. (O simplemente inclúyalos, ya que no duelen.)
Scott

Esto es realmente genial. Aterricé aquí buscando algo similar donde no estaba seguro de antemano cuántos argumentos iba a recibir que tenía que poner en la línea de comando del siguiente argumento. hizo algo asíawk -F'\t' '/match/{printf $1"\0"$2"\0"}' | xargs -0 printf -- '-args1 "%s" -args2 "%s"' | xargs mycommand
keithpjolley

@keithpjolley, su uso de -0en el primero xargspara hacerlo más confiable es derrotado por no usarlo en el segundo. Además, el primer argumento para printf(tanto la utilidad independiente como awkla printf()función de s ) es el formato, no debe usar variables allí. Aquí puedes hacer awk -F'\t' '/match/{printf "-args1\0%s\0-args2\0%s\0", $1, $2}' | xargs -n400 -r0 mycommand. Una vez más, es -n400necesario asegurarse de xargspasar una serie de argumentos que es un múltiplo de 4. (tenga en cuenta que no todas las awkimplementaciones admiten el uso de este \0tipo aquí).
Stéphane Chazelas

no -0solía hacerlo más confiable, lo usaba para que hiciera lo que quería hacer, lo que hace.
keithpjolley

2

prueba esto:

echo {1..8} |xargs -n 2 bash -c 'echo "the number $0 comes before $1"'

2
Esto funcionaría en este caso, pero es mejor ejecutar el sh -cscript con sh(o lo que sea) en $0. Tenga en cuenta que $0no se incluye $@si el sh -cguión iba a utilizarlo , por ejemplo, si el guión eraecho "the two numbers were $@"
Kusalananda
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.