find -exec + vs find | xargs: ¿cuál elegir?

32

Entiendo que -execpueden tomar una +opción para imitar el comportamiento de xargs. ¿Hay alguna situación en la que prefiera una forma sobre la otra?

Personalmente, prefiero la primera forma, aunque solo sea para evitar el uso de una tubería. Creo que los desarrolladores de finddeben haber hecho las optimizaciones apropiadas. ¿Estoy en lo correcto?

rahmu
fuente

Respuestas:

21

Es posible que desee encadenar llamadas para encontrar (una vez, cuando se enteró, que es posible, que podría ser hoy). Por supuesto, esto solo es posible mientras permanezca en búsqueda. Una vez que se conecta a xargs está fuera de alcance.

Pequeño ejemplo, dos archivos a.lst y b.lst:

cat a.lst
fuddel.sh
fiddel.sh

cat b.lst
fuddel.sh

No hay truco aquí, simplemente el hecho de que ambos contienen "fuddel" pero solo uno contiene "fiddel".

Supongamos que no lo sabíamos. Buscamos un archivo que coincida con 2 condiciones:

find -exec grep -q fuddel {} ";" -exec grep -q fiddel {} ";" -ls
192097    4 -rw-r--r--   1 stefan   stefan         20 Jun 27 17:05 ./a.lst

Bueno, tal vez conozca la sintaxis de grep u otro programa para pasar ambas cadenas como condición, pero ese no es el punto. Aquí se puede usar cualquier programa que pueda devolver verdadero o falso, dado un archivo como argumento, grep fue solo un ejemplo popular.

Y tenga en cuenta que puede seguir find -exec con otros comandos find, como -ls o -delete o algo similar. Tenga en cuenta que eliminar no solo rm (elimina archivos), sino que rmdir (elimina directorios) también.

Dicha cadena se lee como una combinación AND de comandos, siempre que no se especifique lo contrario (es decir, con un -orinterruptor (y parens (que necesitan enmascaramiento))).

Así que no te vas de la cadena de búsqueda, lo cual es algo útil. No veo ninguna ventaja en el uso de -xargs, ya que debes tener cuidado al pasar los archivos, que es algo que find no necesita hacer: maneja automáticamente pasar cada archivo como un argumento único para ti.

Si cree que necesita un poco de enmascaramiento para los corchetes find {} , no dude en visitar mi pregunta que solicita evidencia. Mi afirmación es: no lo haces.

usuario desconocido
fuente
3
Esta publicación me ha abierto los ojos a una nueva forma de usar find. ¡Muchas gracias!
rahmu
1
"No veo ninguna ventaja en usar -xargs". ¿Cuál es la -execforma de hacerlo xargs -P4para que tres de los cuatro núcleos no permanezcan inactivos?
Damian Yerrick
1
@DamianYerrick: finalice el comando -exec no en ";" pero con un + (/ signo más).
usuario desconocido
25

La canalización segura de los nombres de archivos xargsrequiere que su findsoporte sea compatible con la -print0opción y que xargstenga la opción correspondiente para leerlo ( --nullo -0). De lo contrario, los nombres de archivo con caracteres no imprimibles o barras invertidas o comillas o espacios en blanco en el nombre pueden causar un comportamiento inesperado. Por otro lado, find -exec {} +está en la especificación POSIXfind , por lo que es portátil, y es casi tan seguro como find -print0 | xargs -0, y definitivamente más seguro que find | xargs. Me gustaría recomendar no hacer find | xargssin -print0.

jw013
fuente
66
Una notable excepción a la portabilidad de find … -exec … {} +OpenBSD es, que solo adquirió esta característica con la versión 5.1 lanzada en 2012. Todos los BSD han tenido -print0durante varios años, incluso OpenBSD (aunque también resistió esa característica por un tiempo). Solaris, por otro lado, se adhiere a las funciones POSIX, por lo que obtienes -exec +y no -print0.
Gilles 'SO- deja de ser malvado'
-print0es un dolor y, aunque se puede argumentar xargs --delimiter "\n"que no es equivalente, nunca he usado el primero después de descubrir el último.
Sridhar Sarnobat
3
No veo cómo -0es más doloroso que --delimiter "\n".
jw013
2
Además -0, GNU xargsdebe -revitar ejecutar el comando si no hay entrada.
Stéphane Chazelas
2
Otro problema | xargs -r0 cmdes que cmdel stdin se ve afectado (dependiendo de la xargsimplementación, es /dev/nullo la tubería.)
Stéphane Chazelas
10

Si usa el -exec ... ;formulario (recordando escapar del punto y coma), está ejecutando el comando una vez por nombre de archivo. Si lo usa -print0 | xargs -0, ejecuta múltiples comandos por nombre de archivo. Definitivamente, debe usar el -exec +formulario, que coloca varios archivos en una sola línea de comando y es mucho más rápido cuando hay una gran cantidad de archivos involucrados.

Una gran ventaja de usar xargses la capacidad de ejecutar múltiples comandos en paralelo usando xargs -P. En sistemas multinúcleo, eso puede proporcionar un gran ahorro de tiempo.

Alexios
fuente
66
Querías decir en -Plugar de -p. Tenga en cuenta xargs -Pque no está en el estándar POSIX, mientras que lo find -exec {} +es, lo que es importante si desea la portabilidad.
jw013
@Alexios No tiene que escapar del signo más, porque no tiene un significado especial para el shell: find /tmp/ -exec ls "{}" +funciona bien.
daniel kullmann
1
Corrent, por supuesto. He estado escapando de todo después -execde tanto tiempo (soy masoquista, ni siquiera uso comillas para escapar {}, siempre escribo \{\}; no preguntes), todo parece que debe escaparse ahora.
Alexios
1
@Alexios: si encuentra un ejemplo (excepto por ser un masoquista) donde el enmascaramiento de los frenos es útil, proporciónelo como respuesta a mi pregunta aquí : afaik, esta pista está desactualizada y solo es un relicto en la página del manual. Nunca he visto un ejemplo en el find /tmp/ -exec ls {} +que no funcionaría.
usuario desconocido
1
Para mí, esta es la memoria muscular que se formó en los días de SunOS 4. Como lo he estado haciendo durante años, no pude darme cuenta por completo cuando bashcomencé a aceptar las llaves literalmente. Estoy bastante seguro de que al menos uno de los viejos proyectiles que he usado arrojó silbidos si no se escaparon los frenos.
Alexios
8

Con respecto al rendimiento, pensé que eso -exec … +sería simplemente mejor porque es una herramienta única que hace todo el trabajo, pero una parte de la documentación de GNU findutil dice que -exec … +podría ser menos eficiente en algunos casos:

[encontrar con -exec … +] puede ser menos eficiente que algunos usos de xargs; por ejemplo, xargspermite construir nuevas líneas de comando mientras el comando anterior aún se está ejecutando, y le permite especificar una cantidad de comandos para ejecutar en paralelo. Sin embargo, la find ... -exec ... +construcción tiene la ventaja de una amplia portabilidad. GNU findutils no admitió ' -exec ... +' hasta la versión 4.2.12 [enero de 2005] ; Una de las razones de esto es que ya tenía la -print0"acción" en cualquier caso.

No estaba exactamente seguro de lo que eso significaba, así que pregunté en el chat dónde derobert lo explicó como:

findprobablemente podría continuar buscando el próximo lote de archivos mientras se -exec … +está ejecutando, pero no lo hace.
find … | xargs …lo hace, porque entonces el hallazgo es un proceso diferente, y sigue ejecutándose hasta que el buffer de la tubería se llena

(Formateando por mí)

Entonces ahí está eso. Pero si el rendimiento realmente importa, tendría que hacer una evaluación comparativa realista o, más bien, incluso preguntarse si incluso querría usar shell para tales casos.

Aquí, en este sitio, creo que es mejor aconsejar a las personas que usen el -exec … +formulario siempre que sea posible porque es más simple y por las razones mencionadas en las otras respuestas aquí (por ejemplo, manejar nombres de archivos extraños sin tener que pensar mucho).

phk
fuente