cat a.txt | xargs -I % echo %
En el ejemplo anterior, xargs toma echo %
como argumento de comando. Pero en algunos casos, necesito múltiples comandos para procesar el argumento en lugar de uno. Por ejemplo:
cat a.txt | xargs -I % {command1; command2; ... }
Pero xargs no acepta este formulario. Una solución que conozco es que puedo definir una función para ajustar los comandos, pero no es una canalización, no lo prefiero. ¿Hay otra solución?
while
bucle que puede contener múltiples comandos.Respuestas:
... o, sin un uso inútil del gato :
Para explicar algunos de los puntos más finos:
El uso de en
"$arg"
lugar de%
(y la ausencia de-I
en laxargs
línea de comandos) es por razones de seguridad: pasar datos ash
la lista de argumentos de la línea de comandos en lugar de sustituirlos en el código evita el contenido que los datos pueden contener (como$(rm -rf ~)
, por ejemplo , ejemplo malicioso) de ser ejecutado como código.Del mismo modo, el uso de
-d $'\n'
es una extensión GNU que hacexargs
que cada línea del archivo de entrada se trate como un elemento de datos separado. Esto o-0
(que espera NUL en lugar de nuevas líneas) es necesario para evitar que los xargs intenten aplicar un análisis similar al shell (pero no del todo compatible) al flujo que lee. (Si no tiene GNU xargs, puede usartr '\n' '\0' <a.txt | xargs -0 ...
para obtener una lectura orientada a la línea sin-d
).El
_
es un marcador de posición para$0
, de modo que otros valores de datos agregados porxargs
convertido$1
y adelante, que resulta ser el conjunto predeterminado de valores sobre los que unfor
ciclo itera.fuente
sh -c
, tenga en cuenta que el punto y coma después de cada comando no es opcional, incluso si es el último comando de la lista.command1
ycommand2
; Más tarde me di cuenta de que no son necesarios.}
:sh -c '{ command1; command2; }' -- but it's not required at the end of a command sequence that doesn't use braces:
sh -c 'command1; comando2 ''%
algún lugar personaje en su cadena pasada ash -c
, entonces este es propenso a las vulnerabilidades de seguridad: Un nombre de fichero que contiene$(rm -rf ~)'$(rm -rf ~)'
(y eso es una subcadena perfectamente legal tener dentro de un nombre de archivo en sistemas de ficheros UNIX comunes!) Hará que alguien un muy mal día .Con GNU Parallel puedes hacer:
Mire los videos de introducción para obtener más información: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
Por razones de seguridad, se recomienda que use su administrador de paquetes para instalar. Pero si no puede hacerlo, puede usar esta instalación de 10 segundos.
La instalación de 10 segundos intentará hacer una instalación completa; si eso falla, una instalación personal; si eso falla, una instalación mínima.
fuente
Este es solo otro enfoque sin xargs ni cat:
fuente
IFS
, ignorará los espacios en blanco iniciales y finales en los nombres de archivo; a menos que agregue-r
, los nombres de archivo con barras diagonales invertidas tendrán esos caracteres ignorados.xargs
. (Esto es difícil de ampliar para hacer algo similar axargs
la-P<n>
opción GNU ' )$ command | while read line; do c1 $line; c2 $line; done
Puedes usar
{} = variable para cada línea en el archivo de texto
fuente
file.txt
contiene un dato con$(rm -rf ~)
una subcadena?Una cosa que hago es agregar a .bashrc / .profile esta función:
entonces puedes hacer cosas como
que es menos detallado que xargs o -exec. También puede modificar la función para insertar el valor de la lectura en una ubicación arbitraria en los comandos de cada uno, si también necesita ese comportamiento.
fuente
Prefiero el estilo que permite el modo de ejecución en seco (sin
| sh
):Funciona también con tuberías:
fuente
-P
la opción ... (Si no es así, que en su mayoría utilizan-exec
enfind
, ya que mis entradas son en su mayoría nombres de archivos)Un poco tarde para la fiesta.
Utilizo el siguiente formato para comprimir mis directorios con miles de archivos pequeños antes de migrar. Si no necesita comillas simples dentro de los comandos, debería funcionar.
Con alguna modificación, estoy seguro de que será útil para alguien. Probado en
Cygwin
(babun)find .
Encuentre aquí-maxdepth 1
No entre en directorios secundarios! -path .
Excluir. / La ruta actual del directorio-type d
coincide solo con los directorios-print0
Salida separada por bytes nulos \ 0| xargs
Canalizar a xargs La-0
entrada es bytes separados por nulos El-I @@
marcador de posición es @@. Reemplace @@ con entrada.bash -c '...'
Ejecutar comando Bash{...}
Agrupación de comandos&&
Ejecute el siguiente comando solo si el comando anterior salió con éxito (salida 0)Final
;
es importante, de lo contrario fallará.Salida:
Actualización de julio de 2018:
Si te encantan los hacks y jugar, aquí hay algo interesante:
Salida:
Explicación:
- Crear una única secuencia de comandos de línea y almacenarla en una variable
-
xargs
leea.txt
y lo ejecuta comobash
guión-
@@
asegura que cada vez que se pasa una línea completa- Poner
@@
después--
se asegura@@
se toma como entrada posicional parámetro enbash
orden, no unabash
de inicioOPTION
, es decir, como-c
sí mismo que significarun command
--
es mágico, funciona con muchas otras cosas, es decirssh
, inclusokubectl
fuente
find . -type f -print0|xargs -r0 -n1 -P20 bash -c 'f="{}";ls -l "$f"; gzip -9 "$f"; ls -l "$f.gz"'
(Es un poco más fácil al convertir bucles)"$@"
es la única forma de evitar eso ... (con-n1
si desea limitar el número de parámetros))--
el shell lo utiliza para decir que no se aceptarán más opciones. Esto permite que haya un-
after the--
too. Puede obtener un resultado muy interesante y confuso si no lo hace, por ejemplo,grep -r
cuando lo incluye en el patrón-
! Sin embargo, la forma en que lo dices no aclara esto no explica realmente cómo funciona esto. Iirc es una cosa POSIX, pero de todos modos vale la pena señalar esto, creo. Solo algo a considerar. Y me encanta ese bono por cierto!Esta parece ser la versión más segura.
(
-0
se puede eliminar ytr
reemplazar con una redirección (o el archivo se puede reemplazar con un archivo separado por nulos). Está principalmente allí ya que principalmente usoxargs
confind
con-print0
salida) (Esto también podría ser relevante enxargs
versiones sin la-0
extensión)Es seguro, ya que args pasará los parámetros al shell como una matriz cuando lo ejecute. El shell (al menos
bash
) los pasaría como una matriz inalterada a los otros procesos cuando todos se obtengan utilizando["$@"][1]
Si usa
...| xargs -r0 -I{} bash -c 'f="{}"; command "$f";' ''
, la asignación fallará si la cadena contiene comillas dobles. Esto es cierto para cada variante que usa-i
o-I
. (Debido a que se reemplaza en una cadena, siempre puede inyectar comandos insertando caracteres inesperados (como comillas, comillas o signos de dólar) en los datos de entrada)Si los comandos solo pueden tomar un parámetro a la vez:
O con algo menos de procesos:
Si tienes GNU
xargs
u otro con la-P
extensión y desea ejecutar 32 procesos en paralelo, cada uno con no más de 10 parámetros para cada comando:Esto debería ser robusto contra cualquier carácter especial en la entrada. (Si la entrada está separada por un valor nulo). La
tr
versión obtendrá alguna entrada no válida si algunas de las líneas contienen líneas nuevas, pero eso es inevitable con un archivo separado por líneas nuevas.El primer parámetro en blanco para
bash -c
se debe a esto: (Desde labash
página del manual ) (Gracias @clacke)fuente
"$@"
bash -c 'command1 "$@"; command2 "$@";' arbitrarytextgoeshere
bash
with-c
toma primero (después de los comandos) un argumento que será el nombre del proceso, luego toma los argumentos posicionales. Intentabash -c 'echo "$@" ' 1 2 3 4
ver qué sale.Otra posible solución que funciona para mí es algo como:
Tenga en cuenta el 'bash' al final: supongo que se pasa como argv [0] a bash. Sin esta sintaxis, se pierde el primer parámetro de cada comando. Puede ser cualquier palabra.
Ejemplo:
fuente
"$@"
, entonces está dividiendo cadenas y expandiendo globalmente la lista de argumentos.Mi BKM actual para esto es
Es lamentable que esto use perl, que es menos probable que se instale que bash; pero maneja más información que la respuesta aceptada. (Doy la bienvenida a una versión omnipresente que no depende de Perl).
La sugerencia de @ KeithThompson de
es genial, a menos que tenga el carácter de comentario de shell # en su entrada, en cuyo caso parte del primer comando y todo el segundo comando se truncarán.
Los hashes # pueden ser bastante comunes, si la entrada se deriva de una lista del sistema de archivos, como ls o find, y su editor crea archivos temporales con # en su nombre.
Ejemplo del problema:
Vaya, aquí está el problema:
Ahh, eso está mejor:
fuente
ls | xargs -I % sh -c 'echo 1 "%"; echo 2 "%"'