buscar -exec cmd {} + vs | xargs

Respuestas:

107

La diferencia de velocidad será insignificante.

Pero debes asegurarte de que:

  1. Su secuencia de comandos no asumirá que ningún archivo tendrá espacio, tabulación, etc. en el nombre del archivo; la primera versión es segura, la segunda no.

  2. Su secuencia de comandos no tratará un archivo que comience con " -" como una opción.

Entonces su código debería verse así:

find . -exec cmd -option1 -option2 -- {} +

o

find . -print0 | xargs -0 cmd -option1 -option2 --

La primera versión es más corta y más fácil de escribir, ya que puede ignorar 1, pero la segunda versión es más portátil y segura, ya que " -exec cmd {} +" es una opción relativamente nueva en GNU findutils (desde 2005, muchos sistemas en ejecución aún no la tendrán). y tenía errores recientemente . Además, mucha gente no sabe esto " -exec cmd {} +", como puede ver en otras respuestas.

Tometzky
fuente
4
-print0 también es una opción GNU find (y GNU xargs) que falta en muchos sistemas que no son Linux, por lo que el argumento de portabilidad no es tan válido. Sin embargo, usar solo -print y dejar el -0 de xargs es muy portátil.
dannysauer
7
El punto es que sin -print0 no funciona si hay un archivo con un espacio o tabulación, etc. Esto puede ser una vulnerabilidad de seguridad como si hubiera un nombre de archivo como "foo -o index.html", entonces -o será tratado como una opción. Pruebe en un directorio vacío: "touch - foo \ -o \ index.html; find. | Xargs cat". Obtendrá: "gato: opción inválida - 'o'"
Tometzky
2
Su ejemplo es un nombre de archivo que contiene un -. Sin -print0, find escupirá ./foo -o index.html. Entonces, tal vez comenzar con un - no es un gran problema, pero el resultado cambia poco y, en un sistema multiusuario, podría proporcionar un vector de ataque si su script es legible por todo el mundo.
bobpaul
2
Una nota sobre algo que me hizo tropezar aquí: el uso execgenerará resultados a medida que se encuentren, mientras xargsque, al parecer, esperará hasta que se busque en todo el directorio antes de escribir en stdout. Si está probando esto en un directorio grande y parece que xargsno está funcionando, se recomienda tener paciencia.
FarmerGedden
1
@Motivated Without -print0find devuelve nombres de archivo separados con una nueva línea, pero la nueva línea también puede ser parte de un nombre de archivo, lo que lo hace ambiguo. El byte 0 no puede, por lo que es un separador seguro. Sí, agregar --a un comando que lo admita es una buena práctica cuando no puede controlar sus argumentos, incluso si no siempre es estrictamente necesario o no es seguro.
Tometzky
7
find . | xargs cmd

es más eficiente (se ejecuta el cmdmenor número de veces posible, a diferencia de exec, que se ejecuta cmduna vez por cada partido). Sin embargo, tendrá problemas si los nombres de archivo contienen espacios o caracteres extravagantes.

Se sugiere utilizar lo siguiente:

find . -print0 | xargs -0 cmd

esto funcionará incluso si los nombres de archivo contienen caracteres extravagantes ( -print0hace que se findimpriman coincidencias terminadas en NUL, -0hace xargsesperar este formato).

Pedir
fuente
28
Esto no es "buscar. -Exec cmd {} \;" pero "encuentra. -exec cmd {} +". Este último no ejecutará un archivo a la vez.
Tometzky
2
Tenga en cuenta que el xargsenfoque es significativamente más lento si no hay (o solo unos pocos) archivos coincidentes y cmdno hay mucho que hacer para cada archivo. Por ejemplo, cuando se ejecuta en un directorio vacío, la xargsversión tardará al menos el doble de tiempo, ya que se deben iniciar dos procesos en lugar de solo uno. (Sí, la diferencia suele ser imperceptible en * nix, pero en un bucle podría ser importante; o, pruébelo en Windows alguna vez ...)
SamB
2

Las xargsversiones modernas a menudo admiten la ejecución de canalizaciones paralelas.

Obviamente, podría ser un punto de inflexión cuando se trata de elegir entre find … -exec y … | xargs

poige
fuente