como uso a opção grep --include para vários tipos de arquivo?

98

Quando quero executar grep em todos os arquivos html em algum diretório, faço o seguinte

grep --include="*.html" pattern -R /some/path

que funciona bem. O problema é como fazer o grep de todos os arquivos html, htm, php em algum diretório?

Deste Use grep --exclude / - incluem sintaxe para não grep através de determinados arquivos , parece que eu posso fazer o seguinte

grep --include="*.{html,php,htm}" pattern -R /some/path

Mas, infelizmente, não funcionaria para mim.
FYI, minha versão grep é 2.5.1.

tianyapiaozi
fonte

Respostas:

137

Você pode usar vários --includesinalizadores. Isso funciona para mim:

grep -r --include=*.html --include=*.php --include=*.htm "pattern" /some/path/

No entanto, você pode fazer como Deruijtersugerido. Isso funciona para mim:

grep -r --include=*.{html,php,htm} "pattern" /some/path/

Não se esqueça de que você pode usar finde xargspara esse tipo de coisa:

find /some/path/ -name "*.htm*" -or -name "*.php" | xargs grep "pattern"

HTH

Steve
fonte
1
Eu vejo o problema. Usei --include = " . {Html, php}" para evitar que o shell se expanda ' ', o que ao mesmo tempo interrompe o shell para expandir {html, php}. Parece que o sinal de igual em --include = * é capaz de impedir que o shell se expanda '*'.
tianyapiaozi
xargs não é realmente um substituto; muitas vezes, quando você precisa desse recurso, está lidando com mais arquivos do que o xargs pode lidar.
James Moore de
2
@JamesMoore: Dê uma olhada no GNU Parallel . Muitas vezes, pode ser usado como um substituto para xargs. Isso também vale uma leitura rápida. HTH.
Steve
3
@tianyapiaozi: Você está correto ao afirmar que a citação em torno da expansão da cinta é o problema; sem as aspas, no entanto, *ainda está sujeito a globbing como parte do token no qual está embutido , apenas acontece de não corresponder a nada neste caso, porque apenas arquivos com o nome literal de algo como --include=foo.htmlcorresponderiam. Para ser seguro, cite o *(o que você pode fazer individualmente \*). Como um bônus adicional, isso torna visualmente mais claro que não é o shell que deve realizar o globbing neste caso.
mklement0
2
Quanto à findsolução: usar em -exec grep "pattern" {} +vez de | xargs grep "pattern"é mais robusto (trata nomes de arquivos com espaços, por exemplo) e também mais eficiente.
mklement0
32

Usando {html,php,htm}só pode funcionar como uma expansão cinta , o que é uma característica fora do padrão (não compatíveis com POSIX) de bash, kshe zsh.

  • Em outras palavras: não tente usá-lo em um script direcionado /bin/sh- use vários argumentos explícitos--include nesse caso.

  • grepem si não entende {...}notação.

Para que uma expansão de chave seja reconhecida, ela deve ser um token sem aspas (parte de um) na linha de comando.

Uma expansão de chave se expande para vários argumentos , portanto, no caso em questão, grepacaba vendo várias --include=... opções, como se você as tivesse passado individualmente.

Os resultados de uma expansão de chave estão sujeitos a globbing (expansão de nome de arquivo) , que tem armadilhas :

  • Cada argumento resultante pode ser expandido para nomes de arquivo correspondentes se ele contiver metacaracteres globbing não citados, como *.
    Embora isso seja improvável com tokens como --include=*.html(por exemplo, você teria que ter um arquivo com o nome literal de algo semelhante --include=foo.htmlpara que algo correspondesse), é importante ter em mente em geral.

  • Se a nullglobopção shell for ativada ( shopt -s nullglob) e globbing não corresponder a nada , o argumento será descartado .

Portanto, para uma solução totalmente robusta , use o seguinte:

grep -R '--include=*.'{html,php,htm} pattern /some/path
  • '--include=*.'é tratado como literal , por estar entre aspas simples ; isso evita a interpretação inadvertida de *um caractere globbing.

  • {html,php,htm}, a - necessariamente - expansão de chaves sem aspas [1] , expande-se para 3 argumentos, que, devido a {...} seguir diretamente o '...'token , incluem esse token.

  • Portanto, após a remoção da citação pelo shell, os três argumentos literais a seguir são finalmente transmitidos paragrep :

    • --include=*.html
    • --include=*.php
    • --include=*.htm

[1] Mais precisamente, são apenas as partes relevantes à sintaxe da expansão da chave que devem ser não citadas, os elementos da lista ainda podem ser citados individualmente e devem ser se contiverem metacaracteres globbing que podem resultar em globbing indesejado após a expansão da chave; embora não seja necessário neste caso, o acima pode ser escrito como
'--include=*.'{'html','php','htm'}

mklement0
fonte
1
Muito obrigado por este post. Grandes postagens não apenas respondem à pergunta, mas ensinam algo novo a você! Isso é especialmente útil para quem está escrevendo sobre algo que precisa ser compatível com POSIX. Qualquer pessoa usando Mac OS X deve olhar aqui!
sabalaba
@sabalaba: Fico feliz em ouvir isso, mas para ser claro: embora a expansão do brace não seja compatível com POSIX, ela funciona bashem qualquer plataforma que bashrode.
mklement0
9

Tente remover as aspas duplas

grep --include=*.{html,php,htm} pattern -R /some/path
Deruijter
fonte
@tianyapiaozi Experimente grep --include=\*.{html,php,htm} pattern -R /some/path. Funcionou para mim
Hyunjun Kim
4

não está funcionando?

  grep pattern  /some/path/*.{html,php,htm} 
Vijay
fonte
Na verdade não. Os arquivos podem residir em um subdiretório do subdiretório
tianyapiaozi de
2

Experimente isso. -r fará uma pesquisa recursiva. -s irá suprimir erros de arquivo não encontrado. -n mostrará o número da linha do arquivo onde o padrão foi encontrado.

    grep "pattern" <path> -r -s -n --include=*.{c,cpp,C,h}
Pradeep
fonte
Esta é a melhor resposta para mim, particularmente, e acho que você pode colocar -rsn em vez de -r -s -n (mas isso é picuinhas).
slim
Normalmente eu uso -rns . Para maior clareza no exemplo, tive que mencionar -r -n -s :-). Fico feliz que ajudou.
Pradeep de
Eu recomendo adicionar -Iao conjunto padrão. Ele pula arquivos binários (que quase nunca são pesquisados), portanto, aumenta a eficiência. Então vamos lá grep -rIns ...que toca acústico bem :)
maldito
2

Funciona com o mesmo propósito, mas sem --includeopção. Ele também funciona no grep 2.5.1.

grep -v -E ".*\.(html|htm|php)"
Kohei Mikami
fonte
0

Use grepcom findcomando

find /some/path -name '*.html' -o -name '*.htm' -o -name '*.php' -type f 
 -exec grep PATTERN {} \+

Você pode usar as opções -regexe -regextypetambém.

Príncipe John Wesley
fonte