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