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 {} \+
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?
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 ...).
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 .
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 {} +
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:
grep pensará que há dois e usará o modo de saída de vários arquivos. 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')
Tags command-line grep