2010-09-22 14 views
29

que tengo una entrada de la fuente, input.txtxargs con múltiples argumentos

a.txt 
b.txt 
c.txt 

que quieren alimentar a éstos de entrada en un programa como el siguiente:

my-program --file=a.txt --file=b.txt --file=c.txt 

así que trato de usar xargs, pero sin suerte.

cat input.txt | xargs -i echo "my-program --file"{} 

Da

my-program --file=a.txt 
my-program --file=b.txt 
my-program --file=c.txt 

Pero quiero

my-program --file=a.txt --file=b.txt --file=c.txt 

Alguna idea?

Respuesta

20

Ninguna de las soluciones dadas hasta ahora ofertas correctamente con los nombres de archivo que contienen espacio. Algunos incluso fallan si los nombres de archivo contienen 'o'. Si sus archivos de entrada son generados por usuarios, debe estar preparado para nombres de archivos sorprendentes.

GNU Parallel se adapta muy bien a estos nombres de archivos y le brinda (al menos) 3 diferentes . las soluciones Si el programa se lleva a 3 y sólo 3 argumentos entonces esto va a trabajar:

(echo a1.txt; echo b1.txt; echo c1.txt; 
echo a2.txt; echo b2.txt; echo c2.txt;) | 
parallel -N 3 my-program --file={1} --file={2} --file={3} 

O:

(echo a1.txt; echo b1.txt; echo c1.txt; 
echo a2.txt; echo b2.txt; echo c2.txt;) | 
parallel -X -N 3 my-program --file={} 

Sin embargo, si su programa tiene tantos argumentos como quepan en la línea de comandos:

(echo a1.txt; echo b1.txt; echo c1.txt; 
echo d1.txt; echo e1.txt; echo f1.txt;) | 
parallel -X my-program --file={} 

ver el vídeo de introducción para aprender más: http://www.youtube.com/watch?v=OpaiGYxkSuQ

+0

Interesante - no sabía nada sobre GNU Parallel. Bash es una cáscara sana; no es necesario colocar una barra invertida después de una tubería para indicarle que el resto del comando está en la línea siguiente. –

+0

GNU paralelo es genial. Una palabra de advertencia: en algunos sistemas, debe dar la opción "--gnu" en paralelo para que funcione con sensatez. Nunca más uso xargs. Si realmente no desea paralelizar, siempre puede darle la opción "-j 1" (1 trabajo). – travc

+0

Utilite 'parallel' no siempre está disponible, especialmente en Unix simple y necesita ser instalado si es posible. Existe una solución interesante [a continuación] (http://stackoverflow.com/a/25623391/2969544) disponible con herramientas standart Unix. – oklas

1

Es porque echo imprime una nueva línea. Pruebe algo como

echo my-program `xargs --arg-file input.txt -i echo -n " --file "{}` 
+1

¿Qué sucede cuando la entrada llega a 30,000 nombres de archivo? –

+0

Usa la expansión subshell, como 'echo my-program $ (xargs --arg-file input.txt -i echo -n" --file "{})' – thiagowfx

5

Se puede utilizar como prefijo sed--file= a cada línea y luego llamar xargs:

sed -e 's/^/--file=/' input.txt | xargs my-program 
+1

Después de Google'ing esto (cuatro años después), vine con mi propia solución (similar) ... específicamente, para esta pregunta, sería más como: 'echo a.txt b.txt c.txt | xargs | sed '//--file =/g' | xargs echo my-program --file' Mi solución complicada era más para canalizar nombres de archivos (como registros de Apache) en una larga línea de comandos. Por ejemplo: 'ls /var/log/apache2/*access.log | xargs | sed 's// -f/g' | xargs echo myprogram -f' – RVT

0

xargs no funciona de esa manera. Proveedores:

 
    myprogram $(sed -e 's/^/--file=/' input.txt) 
14

¿Qué tal:

echo $'a.txt\nb.txt\nc.txt' | xargs -n 3 sh -c ' 
    echo my-program --file="$1" --file="$2" --file="$3" 
' argv0 
1

que estaba buscando una solución para este problema exacto y llegaron a la conclution de codificación de una secuencia de comandos en el medio.

para transformar la salida estándar para la próxima ejemplo utilizar la -n '\ n' delimitador

ejemplo:

[email protected]:~$ echo "file1.txt file2.txt" | xargs -n1 ScriptInTheMiddle.sh 

inside the ScriptInTheMidle.sh: 
!#/bin/bash 
var1=`echo $1 | cut -d ' ' -f1 ` 
var2=`echo $1 | cut -d ' ' -f2 ` 
myprogram "--file1="$var1 "--file2="$var2 

Para que esta solución funcione es necesario tener un espacio entre los argumentos fichero1 .txt y archivo2.txt, o cualquier delímetro que elijas, una cosa más, dentro del script asegúrate de marcar -f1 y -f2 ya que significan "tomar la primera palabra y tomar la segunda palabra" dependiendo de la posición del primer delímetro encontrada (los delimeters podrían ser ' ' ';'....'' lo que usted desee entre comillas simples añadir tantos parámetros como desee

Problema resuelto usando xargs, cortar y algunas secuencias de comandos de bash

Saludos

si! quieres pasar tengo algunos consejos útiles http://hongouru.blogspot.com

3

Aquí hay una solución n usando sed durante tres argumentos, pero está limitado en que se aplica la misma transformación para cada argumento:

cat input.txt | sed 's/^/--file=/g' | xargs -n3 my-program 

Aquí es un método que funcione para dos argumentos, pero permite una mayor flexibilidad:

cat input.txt | xargs -n 2 | xargs -I{} sh -c 'V="{}"; my-program -file=${V% *} -file=${V#* }' 
43

No hagas caso a todos ellos :) solo vistazo a este ejemplo:

echo argument1 argument2 argument3 | xargs -l bash -c 'echo this is first:$0 second:$1 third:$2' | xargs 

salida será

this is first:argument1 second:argument2 third:argument3 
+7

ha. "No los escuches a todos" me río. – user3751385

+5

Si está intentando hacer esto en OSX, use -L1 e.g. 'echo argumento1 argumento2 argumento3 | xargs -L1 bash -c 'echo esto es lo primero: $ 0 segundo: $ 1 tercero: $ 2' | xargs' –

+1

Pero creo que esta respuesta es incorrecta. ¡El archivo tiene 3 líneas pero en esta respuesta hay 3 argumentos en 1 línea! –

0

Nadie ha mencionado haciendo eco a partir de un bucle sin embargo, así que voy a poner esto en aras de la exhaustividad (sería mi segundo enfoque, siendo la sed la primera):

for line in $(< input.txt) ; do echo --file=$line ; done | xargs echo my-program 
0

tropecé en un problema similar y encontré una solución que creo que es más agradable y más limpia que las presentadas hasta ahora.

La sintaxis para xargs que he acabado con sería (por su ejemplo):

xargs -I X echo --file=X 

con un ser línea de comandos completa:

my-program $(cat input.txt | xargs -I X echo --file=X) 

que funcionará como si

my-program --file=a.txt --file=b.txt --file=c.txt 

se realizó (siempre que input.txt contenga datos de su ejemplo).


En realidad, en mi caso tenía que encontrar primero los archivos y también necesitaba de ellos ordenados por lo que mi línea de comandos es el siguiente:

my-program $(find base/path -name "some*pattern" -print0 | sort -z | xargs -0 -I X echo --files=X) 

Pocos detalles que podrían no estar claro (que no eran para me):

  • some*pattern podrá ser citado porque de lo contrario se ampliaría que antes de pasar a find.
  • -print0, luego -z y finalmente -0 usan null-separation para garantizar el manejo adecuado de los archivos con espacios u otros nombres con cable.

Sin embargo, tenga en cuenta que no lo he probado profundamente todavía. Aunque parece estar funcionando.

0

En realidad, es relativamente fácil:

... | sed 's/^/--prefix=/g' | xargs echo | xargs -I PARAMS your_cmd PARAMS

El sed 's/^/--prefix=/g' es opcional, en caso de que necesite para prefijar cada parámetro con un poco de --prefix =.

El xargs echo convierte la lista de líneas de param (un param en cada línea) en una lista de parámetros en una sola línea y xargs -I PARAMS your_cmd PARAMS le permite ejecutar un comando, colocando los parámetros donde quiera.

Así que cat input.txt | sed 's/^/--file=/g' | xargs echo | xargs -I PARAMS my-program PARAMS hace lo que necesita (suponiendo que todas las líneas dentro de input.txt son simples y califican como un único valor de parámetro cada una).

Cuestiones relacionadas