Use a sintaxe grep --exclude / - include para não grep através de certos arquivos


780

Estou procurando a string foo=nos arquivos de texto em uma árvore de diretórios. Está em uma máquina Linux comum, tenho o shell bash:

grep -ircl "foo=" *

Nos diretórios também existem muitos arquivos binários que correspondem a "foo =". Como esses resultados não são relevantes e retardam a pesquisa, desejo que o grep pule a pesquisa desses arquivos (principalmente imagens JPEG e PNG). Como eu faria isso?

Eu sei que existem as opções --exclude=PATTERNe --include=PATTERN, mas qual é o formato do padrão? A página de manual do grep diz:

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

A pesquisa no grep include , grep include exclude , grep exclude e as variantes não encontraram nada relevante

Se existe uma maneira melhor de grepping apenas em certos arquivos, sou a favor; mover os arquivos incorretos não é uma opção. Não consigo pesquisar apenas determinados diretórios (a estrutura de diretórios é uma grande bagunça, com tudo em todo lugar). Além disso, não consigo instalar nada, por isso tenho a ver com ferramentas comuns (como grep ou a localização sugerida ).


13
Apenas FYI, os argumentos utilizados: -C contar as partidas em arquivo -i -l case-insensitive única Mostrar arquivos correspondentes -r recursiva
— Piskvor deixou o prédio

68
Uma maneira mais rápida para excluir diretórios SVN é --exclude-dir=.svn, então grep não vai para eles em tudo
— orip

25
Alguns pontos pedantes que as pessoas precisam saber: 1. Observe a falta de aspas ao redor do globo aqui: --exclude = ' . {Png, jpg}' não funciona (pelo menos com a minha versão grep do GNU) porque grep não suporta {} em seus globs. O exposto acima é expandido em shell para '--exclude = .png --exclude = *. Jpg' (assumindo que nenhum arquivo corresponde ao cwd - altamente improvável, pois você normalmente não inicia nomes de arquivos com '--exclude ='), que grep gosta muito bem. 2. --exclude é uma extensão GNU e não faz parte da definição de grep do POSIX, portanto, se você escrever scripts usando isso, saiba que eles não serão necessariamente executados em sistemas não-GNU.
— IJW

2
Exemplo completo de uso de exclusão de diretório:grep -r --exclude-dir=var "pattern" .
— Enviado

Respostas:


767

Use a sintaxe globbing do shell:

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

A sintaxe para --excludeé idêntica.

Observe que a estrela é escapada com uma barra invertida para impedir que ela seja expandida pelo shell (citá-la, como --include="*.{cpp,h}", também funcionaria). Caso contrário, se você tivesse algum arquivo no diretório de trabalho atual que correspondesse ao padrão, a linha de comando seria expandida para algo como grep pattern -r --include=foo.cpp --include=bar.h rootdir, que pesquisaria apenas arquivos nomeados foo.cppe bar.h, o que provavelmente não é o que você queria.


8
Eu não sei por que, mas eu tinha que citar o padrão como este incluem:grep pattern -r --include="*.{cpp,h}" rootdir
— Topek

6
@topek: Bom ponto - se você tiver arquivos .cpp / .h no diretório atual, o shell expandirá o globo antes de chamar o grep, para que você acabe com uma linha de comando como a grep pattern -r --include=foo.cpp --include=bar.h rootdirque só pesquisará arquivos nomeado foo.cppou bar.h. Se você não possui nenhum arquivo que corresponda ao glob no diretório atual, o shell passa o glob para grep, que o interpreta corretamente.
— Adam Rosenfield

6
Acabei de perceber que o glob é usado apenas para corresponder ao nome do arquivo. Para excluir um diretório inteiro, é necessário ter uma --exclude-diropção. As mesmas regras se aplicam. Somente o nome do arquivo do diretório é correspondido, não um caminho.
— Krzysztof Jabłoński

3
--includeparece não funcionar depois --exclude. Suponho que não faça sentido sequer tentar, exceto que eu tenho aliasque grep com uma longa lista de --excludee --exclude-dir, que eu uso para pesquisar código, ignorando bibliotecas e trocando arquivos e outras coisas. Eu teria esperado que grep -r --exclude='*.foo' --include='*.bar'iria trabalhar, para que eu pudesse limitar a minha aliasa --include='*.bar'única, mas parece ignorar o --includee incluem tudo o que não é um arquivo .foo. Trocar a ordem do --includee --excludefunciona, mas, infelizmente, isso não é útil para o meu alias.
— Michael Scheper

1
como podemos ler a mente de alguém para obter regras para isso PATTERN. Metade da hora eu não consigo encontrar nenhuma descrição do que eles estão esperando lá para
— Arkady

221

Se você quiser apenas pular arquivos binários, sugiro que olhe para a opção -I(maiúscula i). Ele ignora arquivos binários. Eu uso regularmente o seguinte comando:

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

Ele pesquisa recursivamente, ignora arquivos binários e não procura dentro das pastas ocultas do Subversion, por qualquer padrão que eu queira. Eu tenho o alias como "grepsvn" na minha caixa no trabalho.


1
Obrigado, isso é muito útil para alguns outros cenários que encontrei.
— Piskvor saiu do prédio 21/10/08

25
--exclude-dirnão está disponível em qualquer lugar. minha caixa RH no trabalho com o GNU grep 2.5.1 não a possui.
— gcb 18/05/12

Alguma sugestão para o que usar quando --exclude-dirnão estiver disponível? Em todas as minhas tentativas, --excludenão parece se encaixar na conta.
— JMTyler # 31/14

Você sempre pode baixar a fonte grep mais recente do GNU e fazer um 'configure; faço; sudo make install '. Essa é uma das primeiras coisas que faço em uma distribuição Linunx para Mac ou mais antiga.
— Jonathan Hartley

3
Exatamente o que eu precisava. Na verdade, eu uso o git. Então --exclude-dir="\.git",. :-)
— Ionică Bizău

66

Por favor, dê uma olhada no ack , projetado para exatamente essas situações. Seu exemplo de

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

é feito com ack como

ack -icl "foo="

porque ack nunca procura em arquivos binários por padrão e -r está ativado por padrão. E se você quiser apenas arquivos CPP e H, faça

ack -icl --cpp "foo="

Parece bom, tentarei a versão independente do Perl na próxima vez, obrigado.
— Piskvor saiu do prédio 21/10/08

5
Boa ligação, não posso mais viver sem ack.
— Chance

1
stackoverflow.com/questions/667471/… - Isso permitirá que você ack no Windows, se é aí que você está executando o grep.
— TamusJRoyce

@Chance Talvez você quer silversearcher-ag , apenas apt-getno Ubuntu :)
— Justme0

não deve ser confundido comawk
— jasonleonhard 24/03

35

O grep 2.5.3 introduziu o parâmetro --exclude-dir, que funcionará da maneira que você deseja.

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

Você também pode definir uma variável de ambiente: GREP_OPTIONS = "- exclude-dir = .svn"

Vou segundo Andy voto para ack , porém, é o melhor.


7
+1 por mencionar o número exato da versão; Eu tenho o grep 2.5.1 e a opção exclude-dir não está disponível #
— James

25

Descobri isso depois de muito tempo, você pode adicionar várias inclusões e exclusões como:

grep "z-index" . --include=*.js --exclude=*js/lib/* --exclude=*.min.js

5
É melhor combiná-los em uma lista como: --exclude = {pattern1, pattern2, pattern3}
— Yasser Sinjab

12

O comando sugerido:

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

está conceitualmente errado, porque --exclude funciona com o nome da base. Em outras palavras, ele ignorará apenas o .svn no diretório atual.


3
Sim, isso não funciona para mim. O que funcionou para mim foi: exclude-dir = .svn
— Taryn East

2
@ Nicola obrigado! Eu tenho arrancado meu cabelo por que isso não vai funcionar. Diga-me, existe uma maneira de descobrir isso na página de manual? Tudo o que diz é que corresponde a "PATTERN". A página de edição do EDIT diz "arquivo", conforme explicado aqui fixunix.com/unix/…
— 13ren 29/06/11

11

No grep 2.5.1, você deve adicionar esta linha ao perfil ~ / .bashrc ou ~ / .bash

export GREP_OPTIONS="--exclude=\*.svn\*"

9

Acho que a saída do grepping grep é muito útil às vezes:

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

No entanto, isso na verdade não impede a pesquisa nos arquivos binários.


10
Você pode usar grep -Ipara pular arquivos binários.
— 18719 Nathan Fellman

também tem feito que quando eu era jovem ... agora eu sei melhor e quando confrontado com um problema, a primeira coisa é RTFM
— gcb

grepping grep removerá os realces das cores.
— Max Li

7

Se você não tem aversão ao uso find, eu gosto do seu -prunerecurso:

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

Na primeira linha, você especifica o diretório que deseja pesquisar. .(diretório atual) é um caminho válido, por exemplo.

Na 2ª e 3ª linhas, utilização "*.png", "*.gif", "*.jpg", e assim por diante. Use tantas dessas -o -name "..." -pruneconstruções quanto os padrões.

Na quarta linha, você precisa de outro -o(que especifique "ou" para find), os padrões que você deseja e precisa de um -printou -print0no final dele. Se você quer apenas "tudo" o que resta após a poda a *.gif, *.png, etc. imagens, em seguida, usar -o -print0e está feito com a linha 4.

Finalmente, na quinta linha, está o canal no xargsqual cada um desses arquivos resultantes é armazenado em uma variável FILENAME. Em seguida, ele passa grepos -IRsinalizadores, "pattern"e FILENAMEé expandido xargspara se tornar a lista de nomes de arquivos encontrados por find.

Para sua pergunta em particular, a declaração pode ser algo como:

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


Uma alteração que eu sugiro: incluir -falseimediatamente após cada -pruneassim esquecer de usar -print0ou algum tipo de execcomando não irá realmente imprimir os arquivos que você queria excluir: -name "*.png" -prune -false -o name "*.gif -prune -false...
— OnlineCop

7

No CentOS 6.6 / Grep 2.6.3, tenho que usá-lo assim:

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

Observe a falta de sinais de igual "=" (caso contrário --include, --exclude, include-dire --exclude-dirsão ignorados)


6

git grep

Uso git grepotimizado para desempenho e que visa pesquisar determinados arquivos.

Por padrão, ele ignora arquivos binários e está honrando o seu .gitignore. Se você não está trabalhando com a estrutura do Git, ainda pode usá-lo passando --no-index.

Exemplo de sintaxe:

git grep --no-index "some_pattern"

Para mais exemplos, consulte:


5

Eu sou um diletante, sem dúvida, mas eis a aparência do meu ~ / .bash_profile:

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

Observe que, para excluir dois diretórios, eu tive que usar --exclude-dir duas vezes.



3

Se você pesquisar de forma não recursiva, poderá usar padrões glop para corresponder aos nomes dos arquivos.

grep "foo" *.{html,txt}

inclui html e txt. Ele pesquisa apenas no diretório atual.

Para pesquisar nos subdiretórios:

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

Nos subsubdiretórios:

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

3

Nos diretórios também existem muitos arquivos binários. Não consigo pesquisar apenas determinados diretórios (a estrutura de diretórios é uma grande bagunça). Existe uma maneira melhor de grepping apenas em determinados arquivos?

ripgrep

Essa é uma das ferramentas mais rápidas projetadas para pesquisar recursivamente seu diretório atual. Está escrito em Rust , construído sobre o mecanismo regex da Rust para máxima eficiência. Verifique a análise detalhada aqui .

Então você pode simplesmente executar:

rg "some_pattern"

Ele respeita o seu .gitignoree ignora automaticamente arquivos / diretórios ocultos e arquivos binários.

Você ainda pode personalizar incluir ou excluir arquivos e diretórios usando -g/ --glob. Regras de globbing correspondem a .gitignoreglobs. Procure man rgajuda.

Para mais exemplos, consulte: Como excluir alguns arquivos que não correspondem a determinadas extensões com grep?

No macOS, você pode instalar via brew install ripgrep.


3

find e xargs são seus amigos. Use-os para filtrar a lista de arquivos em vez de grep --exclude

Tente algo como

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

A vantagem de se acostumar com isso é que ele pode ser expandido para outros casos de uso, por exemplo, para contar as linhas em todos os arquivos não png:

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

Para remover todos os arquivos não png:

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

etc.

Conforme apontado nos comentários, se alguns arquivos tiverem espaços em seus nomes, use -print0-os xargs -0.


1
Isso não funciona em nomes de arquivos com espaços, mas esse problema é facilmente resolvido usando print0 em vez de print e adicionando a opção -0 ao xargs.
— 21811 Adam Rosenfield

2

esses scripts não cumprem todo o problema ... Tente isso melhor:

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

esse script é muito melhor porque usa expressões regulares "reais" para evitar diretórios de pesquisa. basta separar os nomes de pastas ou arquivos com "\ |" no grep -v

Aproveite! encontrado no meu shell linux! XD


2

Veja @ este.

grep --exclude="*\.svn*" -rn "foo=" * | grep -v Binary | grep -v tags

2
Coisas que atingem aproximadamente isso foram abordadas em outras postagens; além do mais, isso está errado, pois com várias opções de layout configuradas, ele atrapalha os números das linhas e coisas assim ou exclui as linhas de contexto desejadas.
— Chris Morgan

como você pode usar várias opções "-v" ao mesmo tempo?
— Abra o caminho

1

A --binary-files=without-matchopção para o GNU grepfaz com que ele pule arquivos binários. (Equivalente à -Iopção mencionada em outro lugar.)

(Isso pode exigir uma versão recente do grep; 2.5.3, pelo menos.)


1

adequado para o arquivo tcsh .alias:

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

Demorei um pouco para descobrir que a parte {mm, m, h, cc, c} NÃO deveria estar entre aspas. ~ Keith


0

Para ignorar todos os resultados binários do grep

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

A parte awk filtrará todo o arquivo binário foo corresponde às linhas


-2

Tente o seguinte:

  1. Crie uma pasta chamada " --F" sob currdir .. (ou vincule outra pasta lá renomeada para " --F" ou seja double-minus-F.
  2. #> grep -i --exclude-dir="\-\-F" "pattern" *
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.