Utilice grep --exclude / - incluya la sintaxis para no grep a través de ciertos archivos

780

Estoy buscando la cadena foo=en archivos de texto en un árbol de directorios. Está en una máquina Linux común, tengo bash shell:

grep -ircl "foo=" *

En los directorios también hay muchos archivos binarios que coinciden con "foo =". Como estos resultados no son relevantes y ralentizan la búsqueda, quiero que grep omita la búsqueda de estos archivos (principalmente imágenes JPEG y PNG). ¿Como podría hacerlo?

Sé que existen las opciones --exclude=PATTERNy --include=PATTERN, pero ¿cuál es el formato del patrón? La página del manual de grep dice:

--include=PATTERN     Recurse in directories only searching file matching PATTERN.
--exclude=PATTERN     Recurse in directories skip file matching PATTERN.

Buscando en grep include , grep include exclude , grep exclude y variantes no encontró nada relevante

Si hay una mejor manera de grepping solo en ciertos archivos, estoy de acuerdo; mover los archivos ofensivos no es una opción. No puedo buscar solo ciertos directorios (la estructura del directorio es un gran desastre, con todo en todas partes). Además, no puedo instalar nada, así que tengo que ver con herramientas comunes (como grep o el hallazgo sugerido ).

Piskvor salió del edificio
fuente
13
Solo para su información, los argumentos utilizados: -c cuenta las coincidencias en el archivo -i no distingue entre mayúsculas y minúsculas -l solo muestra archivos coincidentes -r recursiva
Piskvor salió del edificio el
68
Una forma más rápida de excluir directorios svn es --exclude-dir=.svn, por lo que grep no entra en ellos en absoluto
orip
25
Un par de puntos pedantes que la gente necesita saber: 1. Tenga en cuenta la falta de comillas alrededor del globo aquí: --exclude = ' . {Png, jpg}' no funciona (al menos con mi versión GNU grep) porque grep no admite {} en sus globos. Lo anterior se expande en shell a '--exclude = .png --exclude = *. Jpg' (suponiendo que no coincidan los archivos en el cwd - altamente improbable ya que normalmente no comienza los nombres de archivo con '--exclude =') que A grep le gusta muy bien. 2. --exclude es una extensión de GNU y no forma parte de la definición de grep de POSIX, por lo que si escribe scripts utilizando esto, tenga en cuenta que no necesariamente se ejecutarán en sistemas que no sean GNU.
ijw
2
Ejemplo completo de uso excluir-dir:grep -r --exclude-dir=var "pattern" .
Tisch

Respuestas:

767

Use la sintaxis de shell globbing:

grep pattern -r --include=\*.{cpp,h} rootdir

La sintaxis para --excludees idéntica.

Tenga en cuenta que la estrella se escapa con una barra invertida para evitar que el shell la expanda (citarla, por ejemplo --include="*.{cpp,h}", funcionaría igual de bien). De lo contrario, si tuviera algún archivo en el directorio de trabajo actual que coincidiera con el patrón, la línea de comando se expandiría a algo así como grep pattern -r --include=foo.cpp --include=bar.h rootdir, que solo buscaría archivos con nombre foo.cppy bar.h, lo que probablemente no sea lo que deseaba.

Adam Rosenfield
fuente
8
No sé por qué, pero tenía que citar el patrón de esta manera incluyen:grep pattern -r --include="*.{cpp,h}" rootdir
Topek
66
@topek: Buen punto: si tiene archivos .cpp / .h en su directorio actual, el shell expandirá el glob antes de invocar grep, por lo que terminará con una línea de comando como grep pattern -r --include=foo.cpp --include=bar.h rootdir, que solo buscará archivos nombrado foo.cppo bar.h. Si no tiene ningún archivo que coincida con el glob en el directorio actual, el shell pasa el glob a grep, que lo interpreta correctamente.
Adam Rosenfield
66
Me acabo de dar cuenta de que el globo está acostumbrado a coincidir solo con el nombre del archivo. Para excluir un directorio completo se necesita una --exclude-diropción. Sin embargo, se aplican las mismas reglas. Solo el nombre de archivo del directorio coincide, no una ruta.
Krzysztof Jabłoński
3
--includeNo parece funcionar después --exclude. Supongo que no tiene sentido ni siquiera intentarlo, excepto que tengo aliasque lidiar con una larga lista de --excludey --exclude-dir, que uso para buscar código, ignorando bibliotecas e intercambiando archivos y cosas. Me hubiera esperado que grep -r --exclude='*.foo' --include='*.bar'iba a funcionar, por lo que podría limitar mi aliasa --include='*.bar'solamente, pero parece ignorar el --includee incluyen todo lo que no es un archivo .foo. Cambiar el orden de los --includey --excludefunciona, pero, por desgracia, eso no es útil para mi alias.
Michael Scheper
1
¿Cómo podemos leer la mente de alguien para obtener reglas para esto PATTERN? Media hora no puedo encontrar ninguna descripción de lo que están esperando allí
Arkady
221

Si solo quiere omitir archivos binarios, le sugiero que mire la -Iopción (mayúscula i). Ignora los archivos binarios. Regularmente uso el siguiente comando:

grep -rI --exclude-dir="\.svn" "pattern" *

Busca de forma recursiva, ignora los archivos binarios y no busca dentro de las carpetas ocultas de Subversion, para cualquier patrón que desee. Lo tengo alias como "grepsvn" en mi caja en el trabajo.

rmeador
fuente
1
Gracias, eso es muy útil para algunos otros escenarios que he encontrado.
Piskvor salió del edificio el
25
--exclude-dirNo está disponible en todas partes. mi caja RH en el trabajo con GNU grep 2.5.1 no lo tiene.
gcb
¿Alguna sugerencia sobre qué usar cuando --exclude-dirno está disponible? En todos mis intentos, --excludeno parece ajustarse a la factura.
JMTyler
Siempre puede descargar la última fuente grep de GNU y hacer una 'configuración; hacer; sudo make install '. Esta es una de las primeras cosas que hago en una distribución de Linunx Mac o anterior.
Jonathan Hartley
3
Exactamente lo que necesitaba. En realidad, uso git. Por lo tanto, --exclude-dir="\.git". :-)
Ionică Bizău
66

Eche un vistazo a ack , que está diseñado para exactamente estas situaciones. Tu ejemplo de

grep -ircl --exclude=*.{png,jpg} "foo=" *

se hace con ack como

ack -icl "foo="

porque ack nunca busca en archivos binarios de forma predeterminada, y -r está activado de forma predeterminada. Y si solo quieres archivos CPP y H, entonces solo haz

ack -icl --cpp "foo="
Andy Lester
fuente
Se ve bien, probaré la versión independiente de Perl la próxima vez, gracias.
Piskvor dejó el edificio el
55
Buena decisión, ya no puedo vivir sin un reconocimiento.
Chance
1
stackoverflow.com/questions/667471/… - Esto le permitirá obtener ventanas en Windows, si es desde donde está ejecutando grep.
TamusJRoyce
@Chance Quizás quieras silversearcher-ag , solo apt-geten Ubuntu :)
Justme0
no debe confundirse conawk
jasonleonhard
35

grep 2.5.3 introdujo el parámetro --exclude-dir que funcionará de la manera que desee.

grep -rI --exclude-dir=\.svn PATTERN .

También puede establecer una variable de entorno: GREP_OPTIONS = "- exclude-dir = .svn"

Voy a segundo de Andy voto para ACK sin embargo, es la mejor.

Corey
fuente
77
+1 por mencionar el número de versión exacto; Tengo grep 2.5.1 y la opción excluir-dir no está disponible
James
25

Encontré esto después de mucho tiempo, puede agregar múltiples inclusiones y exclusiones como:

grep "z-index" . --include=*.js --exclude=*js/lib/* --exclude=*.min.js
Rushabh Mehta
fuente
55
Es mejor combinarlos en una lista como: --exclude = {pattern1, pattern2, pattern3}
Yasser Sinjab
12

El comando sugerido:

grep -Ir --exclude="*\.svn*" "pattern" *

es conceptualmente incorrecto, porque --exclude funciona en el nombre base. En otras palabras, se saltará solo el .svn en el directorio actual.


fuente
3
Sí, no funciona en absoluto para mí. El que funcionó para mí fue: exclude-dir = .svn
Taryn East
2
@ Nicola gracias! Me he estado arrancando el pelo sobre por qué esto no funcionará. Dime, ¿hay alguna manera de descubrir esto desde la página de manual? Todo lo que dice es que coincide con "PATRÓN". La página de manual EDITAR dice "archivo", como se explica aquí fixunix.com/unix/…
13ren
11

En grep 2.5.1 debe agregar esta línea al perfil ~ / .bashrc o ~ / .bash

export GREP_OPTIONS="--exclude=\*.svn\*"
deric
fuente
9

Encuentro que la salida de grepping grep es muy útil a veces:

grep -rn "foo=" . | grep -v "Binary file"

Sin embargo, eso en realidad no impide que busque en los archivos binarios.

Aaron Maenpaa
fuente
10
Puede usar grep -Ipara omitir archivos binarios.
Nathan Fellman
También lo hice cuando era joven ... ahora sé mejor y cuando me enfrento a un problema, lo primero es RTFM
mcb
grep grep eliminará los reflejos de color.
Max Li
7

Si no eres reacio a usar find, me gusta su -prunecaracterística:

find [directory] \
        -name "pattern_to_exclude" -prune \
     -o -name "another_pattern_to_exclude" -prune \
     -o -name "pattern_to_INCLUDE" -print0 \
| xargs -0 -I FILENAME grep -IR "pattern" FILENAME

En la primera línea, especifique el directorio que desea buscar. .(directorio actual) es una ruta válida, por ejemplo.

En la 2ª y 3ª líneas, uso "*.png", "*.gif", "*.jpg", y así sucesivamente. Use tantas de estas -o -name "..." -pruneconstrucciones como tenga patrones.

En la cuarta línea, necesita otro -o(especifica "o" a find), los patrones que SI desea, y necesita uno -printo -print0al final. Si lo que desea es "todo lo demás" lo que queda después de la poda del *.gif, *.png, etc. imágenes, a continuación, utilizar -o -print0y que haya terminado con la cuarta línea.

Finalmente, en la quinta línea está la tubería a la xargsque toma cada uno de esos archivos resultantes y los almacena en una variable FILENAME. Luego pasa greplas -IRbanderas, "pattern"y luego FILENAMEse expande xargspara convertirse en esa lista de nombres de archivo encontrados por find.

Para su pregunta en particular, la declaración puede verse algo así como:

find . \
     -name "*.png" -prune \
     -o -name "*.gif" -prune \
     -o -name "*.svn" -prune \
     -o -print0 | xargs -0 -I FILES grep -IR "foo=" FILES

OnlineCop
fuente
Una enmienda sugeriría: incluir -falseinmediatamente después de cada uno, -pruneasí que olvidarse de usar -print0o algún tipo de execcomando en realidad no imprimirá los archivos que desea excluir: -name "*.png" -prune -false -o name "*.gif -prune -false...
OnlineCop
7

En CentOS 6.6 / Grep 2.6.3, tengo que usarlo así:

grep "term" -Hnir --include \*.php --exclude-dir "*excluded_dir*"

Note la falta de igualdad de signos "=" (de lo contrario --include, --exclude, include-diry --exclude-dirson ignorados)

aesede
fuente
6

git grep

Uso git grepque está optimizado para el rendimiento y tiene como objetivo buscar a través de ciertos archivos.

Por defecto ignora los archivos binarios y está honrando su .gitignore. Si no está trabajando con la estructura de Git, aún puede usarla pasando --no-index.

Ejemplo de sintaxis:

git grep --no-index "some_pattern"

Para más ejemplos, ver:

kenorb
fuente
5

Soy un diletante, claro, pero así es como se ve mi ~ / .bash_profile:

export GREP_OPTIONS = "- orl --exclude-dir = .svn --exclude-dir = .cache --color = auto" GREP_COLOR = '1; 32'

Tenga en cuenta que para excluir dos directorios, tuve que usar --exclude-dir dos veces.

4D4M
fuente
3

Si busca de forma no recursiva, puede usar patrones glop para que coincidan con los nombres de archivo.

grep "foo" *.{html,txt}

incluye html y txt. Busca solo en el directorio actual.

Para buscar en los subdirectorios:

   grep "foo" */*.{html,txt}

En los subdirectorios:

   grep "foo" */*/*.{html,txt}
Stéphane Laurent
fuente
3

En los directorios también hay muchos archivos binarios. No puedo buscar solo ciertos directorios (la estructura del directorio es un gran desastre). ¿Hay una mejor manera de grepping solo en ciertos archivos?

ripgrep

Esta es una de las herramientas más rápidas diseñadas para buscar recursivamente su directorio actual. Está escrito en Rust , construido sobre el motor regex de Rust para una máxima eficiencia. Consulte el análisis detallado aquí .

Entonces puedes simplemente ejecutar:

rg "some_pattern"

Respeta .gitignorey omite automáticamente los archivos / directorios ocultos y los archivos binarios.

Aún puede personalizar incluir o excluir archivos y directorios con -g/ --glob. Las reglas globales coinciden con los globales .gitignore. Busca man rgayuda.

Para obtener más ejemplos, consulte: ¿Cómo excluir algunos archivos que no coinciden con ciertas extensiones con grep?

En macOS, puede instalar a través de brew install ripgrep.

kenorb
fuente
3

find y xargs son tus amigos. Úselos para filtrar la lista de archivos en lugar de grep's --exclude

Intenta algo como

find . -not -name '*.png' -o -type f -print | xargs grep -icl "foo="

La ventaja de acostumbrarse a esto es que se puede expandir a otros casos de uso, por ejemplo, para contar las líneas en todos los archivos que no son png:

find . -not -name '*.png' -o -type f -print | xargs wc -l

Para eliminar todos los archivos que no son png:

find . -not -name '*.png' -o -type f -print | xargs rm

etc.

Como se señaló en los comentarios, si algunos archivos pueden tener espacios en sus nombres, use -print0y en su xargs -0lugar.

Andrew Stein
fuente
1
Esto no funciona en nombres de archivos con espacios, pero ese problema se resuelve fácilmente usando print0 en lugar de print y agregando la opción -0 a xargs.
Adam Rosenfield
2

esos scripts no logran todo el problema ... Intente esto mejor:

du -ha | grep -i -o "\./.*" | grep -v "\.svn\|another_file\|another_folder" | xargs grep -i -n "$1"

este script es mucho mejor, porque usa expresiones regulares "reales" para evitar la búsqueda de directorios. simplemente separe los nombres de carpeta o archivo con "\ |" en el grep -v

¡disfrútala! encontrado en mi shell de Linux! XD


fuente
2

Mira @ este.

grep --exclude="*\.svn*" -rn "foo=" * | grep -v Binary | grep -v tags
suhas tawade
fuente
2
Las cosas que logran aproximadamente esto se han cubierto en otras publicaciones; lo que es más, esto está mal, ya que con varias opciones de diseño configuradas, desordenará los números de línea y cosas así o excluirá las líneas de contexto que se deseaban.
Chris Morgan
¿Cómo puedes usar varias opciones "-v" al mismo tiempo?
Abre el camino el
1

La --binary-files=without-matchopción de GNU grephace que omita los archivos binarios. (Equivalente al -Icambio mencionado en otra parte).

(Esto puede requerir una versión reciente de grep; 2.5.3 lo tiene, al menos).

mjs
fuente
1

adecuado para tcsh .alias archivo:

alias gisrc 'grep -I -r -i --exclude="*\.svn*" --include="*\."{mm,m,h,cc,c} \!* *'

Me tomó un tiempo descubrir que la porción {mm, m, h, cc, c} NO debería estar entre comillas. ~ Keith

Keith Knauber
fuente
0

Para ignorar todos los resultados binarios de grep

grep -Ri "pattern" * | awk '{if($1 != "Binary") print $0}'

La parte awk filtrará todos los archivos binarios para que coincidan las líneas

lathomas64
fuente
-2

Prueba esto:

  1. Cree una carpeta llamada " --F" debajo de currdir .. (o vincule otra carpeta allí renombrada como " --F" es decir double-minus-F.
  2. #> grep -i --exclude-dir="\-\-F" "pattern" *
Pila P
fuente