¿Es posible anidar un 'find -exec' dentro de otro 'find -exec'?

14

Algo como lo siguiente es lo que busco, pero mi código no funciona, no importa cómo escapo {}y+ ;

find ./ -maxdepth 1 -type d -name '.*' -exec \
    find {} -maxdepth 1 -type f -name '*.ini' -exec \
        md5sum \{\} \\; \;

Después de ver esta pregunta de Unix - y - Linux , descubrí que el siguiente código funciona, pero no anida encontrar como tal, y sospecho que hay una mejor manera de hacer este trabajo en particular.

find ./ -maxdepth 1 -type d -name '.*' \
-exec bash -c 'for x; do
    find "$x" -maxdepth 1 -type f -name "*.ini" \
    -exec md5sum \{\} \;; \
done' _ {} \+

¿Hay alguna forma de anidar find -execsin la necesidad de invocar un caparazón (como se indicó anteriormente), con todas sus extrañas citas y restricciones de escape?

¿O puede hacerse esto directamente en un solo comando de búsqueda, usando una combinación de sus muchos parámetros?

Peter.O
fuente
44
Si bien es posible hacer lo que está pidiendo, cuando las cosas se ponen tan complejas, cambio a shell o scripts de Perl. Su segundo fragmento de código está haciendo esto más o menos, solo con el script de shell en línea. Las frases heroicas son divertidas, pero son difíciles de entender y, por lo tanto, difíciles de mantener. A menos que este sea un trato único en el que de alguna manera termines siendo bueno, no puedo ver una buena razón para hacerlo que no sea el desafío intelectual.
Warren Young
1
@Warren Young: Ciertamente no creo que el concepto sea complejo, pero supongo que quiere decir que no hay una manera simple de hacerlo find, pero si findno puede hacerlo, ¿ findpor qué es tan venerado (?) Como la herramienta? para usar para encontrar archivos? ... He descubierto que find ./ -maxdepth 2 -path '.*/*.ini' -type f -exec md5sum {} \+funciona bien en mi situación (la referencia de jw013 -pruneme llevó a esto en la página del manual), pero me pregunto si es un método robusto (en géneros). Realmente nunca he usado find(en menos de un año de Linux), ya que locatehe hecho casi todo lo que necesito, por lo que es un territorio desconocido.
Peter.O
1
La -pathprueba es exactamente lo que iba a sugerir. Con esto, deberías poder hacer todo lo que quieras (perdón por la asociación Ace Of Base;))
rozcietrzewiacz

Respuestas:

8

Intentaría usar un solo hallazgo como:

find .*/ -maxdepth 1 -type f -name '*.ini' -execdir md5sum {} +

o incluso (no, finden absoluto, solo con globos)

md5sum .*/*.ini

aunque esto carece de -type fverificación, por lo que solo funciona si no tiene directorios / no archivos que terminan en .ini. Si lo haces, podrías usar

for x in .*/*.ini; do 
    if [ -f "$x" ]; then 
        md5sum "$x"
    fi
done

lo que, sin embargo, perdería la ventaja de necesitar solo una invocación de md5sum.

Editar

Para un método de encadenamiento general y seguro find, puede hacer algo como

find <paths> <args> -print0 | xargs -0 -I{.} find {.} <args for second find> [etc.]
jw013
fuente
Me sale un error con -f(f?), Y luego otro error con -execdir... Cuando reemplazo -execdir con -exec, y / o también reemplazo md5sum con print, no obtengo nada ...
Peter.O
Gracias, por la alternativa ... pero estoy más después de una forma de hacer esto usando find... No es tanto que solo quiera que se resuelva este ejemplo, estoy buscando ideas sobre las formas de find-fu ... Tal vez haya más pelusa que fu en encontrar ... (No lo sé, porque prácticamente nunca lo he usado), y esta es la primera situación que realmente quería usar (para archivos de imagen en realidad) y el -exec de la que he oído hablar tanto parece no ser tan poderoso como su representante (?) alude a ... (+1 para las alternativas, sin embargo) ... pero su findejemplo simplemente no funciona (aún )
Peter.O
Recibo este error para el findcomando: ... find: The relative path ~ / bin 'está incluido en la variable de entorno PATH, que es insegura en combinación con la acción -execdir de find. Por favor, elimine esa entrada de $ PATH` .... Así que tal vez funcione, pero debo decir que he estado tratando de deshacerme de ese ~ / bin por un tiempo ahora ... Tendré que tomar más Míralo seriamente ... No sé dónde lo he puesto ... alguna idea de dónde puede estar al acecho; el ~/binen mi RUTA
Peter.O
Creo que el poder findse aprecia mejor en situaciones que no se pueden hacer completamente con globos, pero como ese tipo de situaciones son raras, normalmente no necesito encontrar mucho.
jw013
Bien .. eso es un punto interesante y buena (sobre el uso de globos) ...
Peter.O
2

Su problema original no requiere llamar a find recursivamente, pero supongo que ese no era el punto.

Creo que no es posible llamar a find de forma recursiva de la manera que desee.

Lo siguiente no es llamar a find recursivamente (o anidar, como se llame) tampoco, pero ¿no puede simplemente tomar un conjunto de resultados del primer find y alimentarlo al segundo? Así es como lo haría instintivamente:

find `find ./ -maxdepth 1 -type d -name '.*'` \
    -maxdepth 1 -type f -name '*.ini' -exec md5sum {} \;

También puede usar xargspara ejecutar el segundo hallazgo.

Actualizar:

Quería agregar eso porque la mayoría de las utilidades de UNIX toman varios argumentos de nombre de archivo en lugar de uno, por lo general, puede evitar por -execcompleto:

md5sum `find \`find ./ -maxdepth 1 -type d -name '.*'\` -maxdepth 1 -type f -name '*.ini'`

Al anidar backticks solo agrega barras invertidas \antes que las internas.

Si imaginamos que md5sumsolo toma un argumento de nombre de archivo, siempre podemos envolverlo en un forbucle:

for f in `find \`find ./ -maxdepth 1 -type d -name '.*'\` -maxdepth 1 -type f -name '*.ini'`
do
    md5sum $f
done

Tenga en cuenta que esto se vuelve más difícil si -están involucrados los nombres de archivo / directorio que comienzan con o que contienen un espacio. Las utilidades de UNIX no funcionan bien con ellas. En ese caso, la adición de ./, --o se necesita comillas.

Obviamente, el ejemplo original no es bueno, porque podríamos hacer:

md5sum .*/*.ini
chasquido
fuente
1
Has dado una buena descripción de la situación, pero todos los findmétodos mostrados reciben un error cuando un archivo / directorio contiene espacios ... md5sum .*/*.iniFunciona bien ... Estoy empezando a tener la sensación general de que * Warren Young * comentar sobre cosas que se vuelven 'complejas' para que findocurran al principio del juego :), pero supongo que se findhace realidad cuando las pruebas de condición son más complejas, pero en lo que respecta a anidar -exec, he descartado la idea, ya que parece que hay formas más sencillas de hacerlo ... (pero perl no es "simple" para mí (todavía) ...
Peter.O
0

Al menos logré anidar 2 comandos de búsqueda:

find ~ -maxdepth 1 -type d -name '.*' -execdir \
    find {} -maxdepth 1 -type f -name '*.ini' \;

Pero no resolví invocar otro -exec (dir) - llamar desde allí.

usuario desconocido
fuente
Sí, ese es exactamente mi problema :)
Peter.O
Sí, pero no anidar 3 no es lo mismo que no anidar 2. :)
usuario desconocido