Minha resposta é semelhante à resposta de @ RomanPerekhrest. A principal diferença é que ele tira proveito do fato de que você pode obter awk
para processar toda a entrada de uma só vez definindo o separador de registro ( RS
) como algo que nunca corresponderá a nada na entrada (por exemplo, ^$
). Em outras palavras, sorve o arquivo inteiro e pesquise-o como se fosse uma única string.
por exemplo,
find . -type f -exec \
awk -v RS='^$' '/foo/ && /bar/ && /baz/ { print FILENAME }' {} +
Isso listará todos os arquivos abaixo do diretório atual ( .
) que contêm ALL das expressões regulares foo
, bar
e baz
. Se você precisar de algumas ou de todas as expressões regulares para serem tratadas como palavras inteiras, coloque-as entre as âncoras de limite de palavras \<
e \>
- por exemplo, \<foo\>
.
Isso também é executado com mais rapidez porque não bifurca awk
uma vez para cada arquivo. Em vez disso, ele executa awk
com tantos argumentos de nome de arquivo que caberão no buffer de linha de comando (normalmente 128K ou 1 ou 2M caracteres em sistemas modernos). Se find
descobrir 1000 arquivos, só será executado awk
uma vez em vez de 1000 vezes.
Observação: isso requer uma versão de awk
que permita que RS
seja uma expressão regular. Veja Slurp-mode no awk? para mais detalhes e um exemplo de como implementar um forma limitada de leitura "modo slurp" em outras versões do awk.
Nota: Isto lerá todo o conteúdo de cada arquivo encontrado na memória, um de cada vez. Para arquivos verdadeiramente enormes, por ex. arquivos de log com dezenas de gigabytes ou maiores em tamanho, isso pode exceder a RAM disponível ou mesmo RAM + SWAP. Por mais improvável que seja, se acontecer, pode causar sérios problemas (por exemplo, no Linux, o kernel começará a matar processos aleatórios se for executado em RAM e SWAP).