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 ).

Piskvor saiu do prédio
fonte
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.

Adam Rosenfield
fonte
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.

rmeador
fonte
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="
Andy Lester
fonte
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.

Corey
fonte
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
Rushabh Mehta
fonte
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.


fonte
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\*"
deric
fonte
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.

Aaron Maenpaa
fonte
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

OnlineCop
fonte
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)

aesede
fonte
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:

kenorb
fonte
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.

4D4M
fonte
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}
Stéphane Laurent
fonte
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.

kenorb
fonte
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.

Andrew Stein
fonte
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


fonte
2

Veja @ este.

grep --exclude="*\.svn*" -rn "foo=" * | grep -v Binary | grep -v tags
suhas tawade
fonte
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.)

mjs
fonte
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

Keith Knauber
fonte
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

lathomas64
fonte
-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" *
Pilha P
fonte