`find` con múltiples` -name` y `-exec` ejecuta solo las últimas coincidencias de` -name`

74

Cuando estoy usando

find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"

encuentra todos los tipos de archivo. Pero cuando agrego -execal final:

find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt" -exec sh -c 'echo "$0"' {} \;

parece que solo imprime .txtarchivos. ¿Qué estoy haciendo mal?

Nota: usando MINGW (Git Bash)

jakub.g
fuente
Sugerencia: el primer comando también imprimirá directorios cuyos nombres coincidan *.js*o *.txt.
Comodín el

Respuestas:

99
encontrar . -type f -name "* .htm *" -o -name "* .js *" -o -name "* .txt"

es la abreviatura de:

encontrar . \ (\ ( -type f -a -name "* .htm *" \) -o \
          \ ( -name "* .js *" \) -o \
          \ ( -name "* .txt" \) \
       \) -una impresión

Es decir, dado que no se especifica un predicado de acción (solo condiciones ), -printse agrega implícitamente una acción para los archivos que coinciden con las condiciones.

(y, por cierto, eso imprimiría .jsarchivos no regulares ( -type fsolo se aplica a los .htmarchivos)).

Mientras:

encontrar . -type f -name "* .htm *" -o -name "* .js *" -o -name "* .txt" \
  -exec sh -c 'echo "$ 0"' {} \;

es la abreviatura de:

encontrar . \ ( -type f -a -name "* .htm *" \) -o \
       \ ( -name "* .js *" \) -o \
       \ ( -name "* .txt" -a -exec sh -c 'echo "$ 0"' {} \; \)

Para find(como en muchos idiomas), AND ( -a; implícito cuando se omite) tiene prioridad sobre OR ( -o), y agregar un predicado de acción explícito (aquí -exec) cancela la -printacción implícita vista anteriormente. Aquí quieres:

find . -type f \( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" \) \
  -exec sh -c 'echo "$0"' {} \;

O:

find . -type f \( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" \) -exec sh -c '
   for i do
     echo "$i"
   done' sh {} +

Para evitar ejecutar uno shpor archivo.

Stéphane Chazelas
fuente
En algunos de esos usos de sh -c, debe agregar el argumento cero para sh (aunque en otros ya lo haya incluido).
James Youngman
1
Esa es una gran respuesta!
Marinos un
30

Son los corchetes implícitos. Añadir corchetes explícitos.\( \)

find . -type f \( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" \) -exec sh -c 'echo "$0"' {} \;

o usando xargs (me gusta xargs me parece más fácil, pero aparentemente no es tan portátil).

find . -type f \( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" \) -print0 | xargs -0 -n1 echo
ctrl-alt-delor
fuente