Me gustaría ejecutar un comando de shell en cada línea tomada de STDIN.
En este caso, me gustaría ejecutar xargs mv
. Por ejemplo, dadas dos líneas:
mfoo foo
mbar bar
Me gustaría ejecutar:
xargs mv mfoo foo
xargs mv mbar bar
Probé las siguientes estrategias con ruby
, awk
y xargs
. Sin embargo, lo estoy haciendo mal:
Justo xargs
:
$ echo "mbar bar\nmbaz baz" | xargs mv
usage: mv [-f | -i | -n] [-v] source target
mv [-f | -i | -n] [-v] source ... directory
A través de awk
:
$ echo "mbar bar\nmbaz baz" | awk '{ system("xargs $0") }'
A través de ruby
:
$ echo "mbar bar\nmbaz baz" | ruby -ne '`xargs mv`'
$ ls
cat foo mbar mbaz
Tengo algunas preguntas:
- ¿Cómo hago lo que estoy intentando hacer?
- ¿Qué hay de malo en cada uno de mis intentos?
- ¿Existe una mejor manera de "pensar" en lo que estoy intentando hacer?
Estoy especialmente confundido porque mi xargs
intento no funciona porque lo siguiente funciona:
$ echo "foo\nbar" | xargs touch
$ ls
bar foo
Respuesta1
echo "mbar bar\nmbaz baz" | xargs mv
Con xargs
deberías usar la -t
opción para ver qué está pasando. Entonces, en el caso anterior, si invocamos xargs
con -t
, ¿qué vemos?
mv mbar bar mbaz baz
Entonces obviamente no es correcto. Lo que sucedió fue que, xargs
como un cocodrilo hambriento, se comió todos los args que le alimentaban a través de la tubería echo
. Entonces necesitas una manera de limitar la liberación de argumentos al cocodrilo. Y dado que solicitó por línea, lo que necesita es la opción -l
o -L
para POSIX.
echo "mbar bar\nmbaz baz" | xargs -l -t mv
Manera POSIX:
echo "mbar bar\nmbaz baz" | xargs -L 1 -t mv
mv mbar bar
mv mbaz baz
Y esto es lo que querías. HT
Respuesta2
Puedes ir de esta manera:
echo -e "foo bar\ndoo dar" | xargs -n 2 mv
Para leer desde el archivo:
cat lines.txt | xargs -n 2 mv
o
xargs -a lines.txt -n 2 mv
Respuesta3
xargs
Puede que no se comporte como espera. Vea el comentario de @MichaelHomer a esta pregunta:
xargs mv mfoo foo
esperará la entrada y ejecutará mvmfoo foo $x_1 $x_2 $x_3...
para cada línea$x_n
de entrada que obtenga. @MichaelHomer
Esto se puede confirmar leyendo elxargs
página de manual:
DESCRIPCIÓN
La utilidad xargs lee cadenas delimitadas por espacios, tabulaciones, nuevas líneas y finales de archivo de la entrada estándar y ejecuta la utilidad con las cadenas como argumentos.
En la práctica, parece que xargs
se ignorarán las nuevas líneas cuando se introduzcan argumentos en la utilidad de línea de comando proporcionada como primer argumento. Por ejemplo, observe lo que sucede con la nueva línea:
$ echo "foo bar\ncat dog"
foo bar
cat dog
$ echo "foo bar\ncat dog" | xargs echo
foo bar cat dog
Este comportamiento se puede controlar con el-n
bandera:
-n numero
Establezca el número máximo de argumentos tomados de la entrada estándar para
cada invocación de utilidad.
Volviendo al ejemplo anterior, si queremos xargs
tomar solo 2 argumentos y luego salir, podemos usarEl enfoque de @ddnomad:
$ echo "foo bar\ncat dog" | xargs -n 2 echo
foo bar
cat dog
Además, como se muestra en los comentarios de la respuesta de Rakesh Sharma, en BSD xargs
puede especificar el número de líneas que se leerán con la -L
bandera. Desde la página de manual:
-Número L
Llame a la utilidad para cada línea numérica leída. Si se alcanza el EOF y
se han leído menos líneas que el número, se llamará a la utilidad con las líneas disponibles.
Igualmente útil para las pruebas es el -t
interruptor:
Revisando nuestro ejemplo, ambos de los siguientes funcionarán; sin embargo, el segundo ejemplo es mejor porque es lo que se pretendía en este caso:
$ echo "foo bar\ncat dog" | xargs -n 2 echo
foo bar
cat dog
$ echo "foo bar\ncat dog" | xargs -L 1 echo
foo bar
cat dog
Nota de la página de manual:
Las opciones -L y -n son mutuamente excluyentes; Se utilizará el último proporcionado.
Respuesta4
Existe una solución muy sencilla que no utiliza xargs.
Defina esta función:
$ mv2() { while (($# >1 )); do echo mv "$1" "$2"; shift 2; done; }
Luego, simplemente llámalo con la lista de nombres de archivos necesarios (no se requieren nuevas líneas):
$ mv2 mbar bar mbaz baz
mv mbar bar
mv mbaz baz
Elimina el eco para que la función realmente funcione.