Executa 'grep' excluindo um arquivo em um caminho específico

10

Desejo excluir o arquivo ./test/main.cpp da minha pesquisa.

Veja o que estou vendo:

$ grep -r pattern --exclude=./test/main.cpp
./test/main.cpp:pattern
./lib/main.cpp:pattern
./src/main.cpp:pattern

Eu sei que é possível obter a saída que eu quero usando vários comandos em um arranjo de pipes e filtros, mas há alguma citação / escape que fará grep entender o que eu quero nativamente?

    
por nobar 20.05.2015 / 16:52

5 respostas

5

grep não pode fazer isso para o arquivo em um determinado diretório se você tiver mais arquivos com o mesmo nome em diretórios diferentes, use find em vez disso:

find . -type f \! -path './test/main.cpp' -exec grep pattern {} \+

    
por 20.05.2015 / 17:15
3

Eu não acho que seja possível com o GNU grep . Você não precisa de canos embora.

com find :

find . ! -path ./test/main.cpp -type f -exec grep pattern {} +

com zsh :

grep pattern ./**/*~./test/main.cpp(.)

(exclui arquivos ocultos, assim como excluir o .git, .svn ...).

    
por 20.05.2015 / 17:20
1

Eu poderia escrever um livro: "A arte perdida de xargs ". O find ... -exec … '; lança um grep para cada arquivo (mas a variante com -exec … + não). Bem, estamos desperdiçando ciclos de CPU hoje em dia, então por que não, certo? Mas se o desempenho, a memória e a energia forem um problema: use xargs:

find . -type f \! -path 'EXCLUDE-FILE' -print0 | xargs -r0 grep 'PATTERN'

A find do -print0 do GNU irá NUL -terminar sua saída e a xargs ' -0 opõe esse formato como entrada. Isso garante que qualquer personagem engraçado que seu arquivo tenha, o pipeline não ficará confuso. A opção -r garante que não há erro no caso de find não encontrar nada.

Note que agora você pode fazer coisas como:

find . -type f -print0 | grep -z -v "FILENAME EXCLUDE PATTERN" | 
  xargs -r0 grep 'PATTERN'

O -z do GNU grep faz a mesma coisa que xargs ' -0 .

    
por 20.05.2015 / 18:50
1

Se o seu find suportar -path , que foi adicionado ao POSIX em 2008, mas ainda está faltando no Solaris:

find . ! -path ./test/main.cpp -type f -exec grep pattern /dev/null {} +
    
por 20.05.2015 / 17:09
0

Para registro, aqui está a abordagem que eu prefiro:

grep pattern $(find . -type f ! -path './test/main.cpp')

Mantendo o grep no início do comando, acho que isso é um pouco mais claro - além disso, ele não desativa o realce de cor de grep . De certo modo, usar find em uma substituição de comando é apenas uma maneira de estender / substituir o subconjunto (limitado) de pesquisa de arquivo da funcionalidade grep .

Para mim, a % sintaxefind -exec é meio misteriosa. Uma complexidade com find -exec é a (às vezes) necessidade de escapar vários caracteres (especialmente se \; for usado no Bash). Apenas para o propósito de colocar as coisas em contextos familiares, os dois comandos a seguir são basicamente equivalentes:

find . ! -path ./test/main.cpp -type f -exec grep pattern {} +
find . ! -path ./test/main.cpp -type f -print0 |xargs -0 grep pattern

Se você quiser excluir subdiretórios , pode ser necessário usar um curinga. Não entendo completamente o esquema aqui - fale sobre arcanos :

grep pattern $(find . -type f ! -path './test/main.cpp' ! -path './lib/*' )

Uma nota adicional para generalizar as soluções find -based para uso em scripts : A linha de comando grep deve incluir a opção -H / --with-filename . Caso contrário, a formatação de saída será alterada sob a circunstância de haver apenas um nome de arquivo nos resultados da pesquisa de find . Isso é notável porque não parece ser necessário se estiver usando a pesquisa de arquivos nativa de grep (com a opção -r ).

... Ainda melhor, porém, é incluir /dev/null como primeiro arquivo a pesquisar. Isso resolve dois problemas:

  • Garante que, se houver um arquivo para pesquisa, grep pensará que há dois e usará o modo de saída de vários arquivos.
  • Garante que, se não houver arquivos para pesquisa, grep pensará que existe um arquivo e não aguardará aguardando stdin.

Então a resposta final é:

grep pattern /dev/null $(find . -type f ! -path './test/main.cpp')
    
por 20.05.2015 / 19:14