¿Cómo ignorar ciertos nombres de archivo usando "buscar"?

143

Uno de mis comandos BASH favoritos es:

find . -name '*.*' -exec grep 'SearchString' {} /dev/null \;

que busca el contenido de todos los archivos en y debajo del directorio actual para el SearchString especificado. Como desarrollador, esto ha sido útil a veces.

Sin embargo, debido a mi proyecto actual y la estructura de mi base de código, me gustaría hacer que este comando BASH sea aún más avanzado al no buscar ningún archivo que esté dentro o debajo de un directorio que contenga ".svn", o cualquier archivo que termina con ".html"

Sin embargo, la página de MAN para encontrar me confundió un poco. Intenté usar -prune, y me dio un comportamiento extraño. En un intento de omitir solo las páginas .html (para comenzar), intenté:

find . -wholename './*.html' -prune -exec grep 'SearchString' {} /dev/null \;

y no obtuve el comportamiento que esperaba. Creo que podría estar perdiendo el punto de -prune. podrían ustedes ayudarme?

Gracias

Cody S
fuente
1
Solo para tu información: findno es un comando bash
incorporado
1
Puede buscar dentro del archivo congrep -rl 'SearchString'
emanuele
@emanuele Hola, bienvenido a SuperUser (y a la red Stack Exchange). Esta es una pregunta que hice y que fue respondida hace 2 años y medio. Por lo general, si desea agregar una respuesta a la pregunta, hágalo desplazándose hacia abajo y respondiendo allí, en lugar de hacerlo en un comentario. Sin embargo, dado que esta pregunta ya tiene una respuesta aceptada (la que tiene la marca de verificación verde), es poco probable que su respuesta reciba mucha atención. FYI.
Cody S
1
Hola, no es una respuesta a tu pregunta. Es solo una sugerencia, como usted indicó en el preámbulo que usa findpara buscar dentro de un archivo.
Emanuele
2
FWIW, -name '*.*'no encuentra todos los archivos: solo aquellos con un .en su nombre (el uso de *.*es típicamente un DOS-ismo, mientras que en Unix, normalmente se usa solo *para eso). Para hacer coincidir realmente a todos, basta con retirar por completo el argumento: find . -exec .... O si solo desea aplicar grep a los archivos (y omitir directorios), entonces hágalo find . -type f -exec ....
Stefan

Respuestas:

197

Puede usar la función de negación (!) De buscar para no hacer coincidir archivos con nombres específicos:

find . ! -name '*.html' ! -path '*.svn*' -exec grep 'SearchString' {} /dev/null \;

Entonces, si el nombre termina en .html o contiene .svn en cualquier parte de la ruta, no coincidirá y, por lo tanto, no se ejecutará el archivo ejecutable.

Pablo
fuente
1
¿Debería especificar -name ' ? 'en algún lugar allí? ¿Haría eso antes o después de las negaciones?
Cody S
¿La intención de su *.*coincidencia era garantizar que solo coincidiera con los archivos que contienen un .? Find coincidirá con todos los archivos en ausencia de una namedirectiva, por lo que lo anterior coincidirá con todo excepto html y svn
Paul
55
Creo que quieres -wholename '*.svn*'más que -name.
fuenfundachtzig
2
Sí, lo hace, de modo que los .svndirectorios se excluyen de los resultados de búsqueda.
fuenfundachtzig
1
@Noumenon ! -name '.'debería excluir .de los resultados de búsqueda.
Paul
11

He tenido el mismo problema durante mucho tiempo, y hay varias soluciones que pueden aplicarse en diferentes situaciones:

  • ack-grepes una especie de "desarrollador grep" que omite por defecto los directorios de control de versiones y los archivos temporales. La manpágina explica cómo buscar solo tipos de archivos específicos y cómo definir los suyos .
  • grepLas opciones --excludey las propias --exclude-dirse pueden usar muy fácilmente para omitir archivos globales y directorios únicos (desafortunadamente, no es necesario buscar directorios).
  • find . \( -type d -name '.svn' -o -type f -name '*.html' \) -prune -o -print0 | xargs -0 grep ... debería funcionar, pero las opciones anteriores son probablemente menos problemáticas a largo plazo.
l0b0
fuente
9

El siguiente findcomando elimina los directorios cuyos nombres contienen .svn , aunque no desciende al directorio, el nombre de la ruta podada se imprime ... (¡ -name '*.svn'es la causa!) ..

Puede filtrar los nombres de directorio a través de: grep -d skipque omite silenciosamente tales "nombres de directorio" de entrada.

Con GNU grep, puede usar en -Hlugar de /dev/null. Como un pequeño problema secundario: \+puede ser mucho más rápido que \;, por ejemplo. para 1 millón de archivos de una línea, usarlo \;tomó 4m20s , usarlo \+solo tomó 1.2s .

El siguiente método utiliza en xargslugar de -exec, y asume que no hay líneas nuevas \nen ninguno de sus nombres de archivo . Como se usa aquí, xargses muy similar a encontrar \+.

xargspuede pasar nombres de archivo que contienen espacios consecutivos cambiando el delimitador de entrada a '\n'con la -dopción

Esto excluye directorios cuyos nombres contienen .svn y greps solo archivos que no terminan en .html.

find . \( -name '*.svn*' -prune  -o ! -name '*.html' \) |
   xargs -d '\n' grep -Hd skip 'SearchString'
Peter.O
fuente
1
Gracias por señalar la \+variante de la acción -exec. ¡Hurra por problemas secundarios leves!
Christian Long
Por supuesto, dado +que no es un carácter especial para el shell, no necesita escribir \antes.
Scott