
Olá, estou tentando percorrer um diretório e todos os seus subdiretórios para encontrar a string 'foo' em todos os arquivos, por exemplo. Quero então exibir os nomes dos arquivos (incluindo o caminho completo) de todos os arquivos que os contêm.
O sistema operacional é unix e usa shell bash.
Qualquer sugestão seria apreciada. Obrigado
Responder1
Você pode usar um recursivo grep
. No GNU grep
, pelo menos, essa é a -R
opção:
grep -R foo /path/to/parent/directory
Se você usar um caminho completo, como acima, por exemplo, /home/callsign223/foo/
todos os arquivos serão mostrados com seus caminhos qualificados. E se você quiser ver apenas os nomes dos arquivos, não as linhas correspondentes, você pode usar -l
para imprimir apenas o nome do arquivo:
grep -lR foo /path/to/parent/directory
Observe que a -R
opção não é portátil e não é suportada por todas grep
as implementações.
Responder2
se grep -R
não for uma opção, você poderá usar find
para executar grep
em cada arquivo:
find ./ -type f -exec grep -Hni "some-string" {} ';'
Responder3
Algo que funcionaria em todos os sistemas Unix atuais é usar find
para localizar os arquivos e, em seguida, grep
identificar os arquivos que contêm a string foo
:
find . -type f -exec grep -l -F -e 'foo' {} +
O comando acima encontraria todos os arquivos regulares no diretório atual ou abaixo dele. Para lotes de arquivos encontrados, grep
seria chamado para localizar a string foo
. Ao localizar a string em um arquivo, grep
gera o nome do caminho do arquivo imediatamente e continua com o próximo arquivo sem ler mais do arquivo atual.
- Usamos
-l
paragrep
parar e relatar o nome do arquivo na primeira linha que corresponde ao padrão fornecido. Isso acelera o processamento, ignorando o bit do arquivo após o primeiro acesso. - Usamos
-F
para fazer com quegrep
o padrão seja considerado uma string em vez de uma expressão regular. Isso potencialmente acelera o processamento ao não tentar desfazer correspondências de expressões regulares e nos permite combinar strings que se parecem com expressões regulares. - Usamos
-e
com o padrão fornecido, caso comece com um travessão. Isso não acontece neste caso, mas substituir essa string estáticafoo
por uma variável introduziria a possibilidade de correspondência com um padrão que começa com um travessão, o que, portanto, seria confundido com uma opção de linha de comando.
No entanto, uma lista de nomes de arquivos geralmente não é boa. Você provavelmente gostaria de fazer algo com esses arquivos. Nesse caso, você faria isso como parte do utilitário find
executado por meio de -exec
:
find . -type f -exec sh -c '
for pathname do
grep -q -F -e "foo" "$pathname" || continue
# Do something with "$pathname" here
done' sh {} +
Aqui chamamos um pequeno script em linha para processar arquivos encontrados em lotes. Verificamos cada arquivo individualmente em busca da string foo
e ignoramos os arquivos que não contêm a string. Onde adicionei um comentário no script in-line, você processaria o arquivo referenciado por "$pathname"
.
Você também pode escrever o acima find
executando grep
separadamente antes de chamar o script in-line:
find . -type f -exec grep -q -F -e 'foo' {} \; -exec sh -c '
for pathname do
# Do something with "$pathname" here
done' sh {} +
Observe como o primeiro -exec
atua como um teste no arquivo atual antes de chamar sh -c
os arquivos que passaram nesse teste.
Responder4
Acredito que o ack
utilitário fará exatamente o que você está procurando. Ele já pode estar instalado em seu sistema. Caso contrário, ele pode ser baixado emhttps://beyondgrep.com/.
Um dos recursos interessantes ack
é que ele ignora arquivos binários por padrão e pode receber opções de linha de comando para restringir os tipos de arquivos pesquisados por algum filtro prescrito ou por tipo de arquivo (por exemplo, por linguagem de programação: --type=cc
irá pesquisar .c
, .h
, .xs
arquivos, --type=awk
irá pesquise quaisquer arquivos que correspondam /awk/
na primeira linha). Esses tipos também podem ser estendidos pelo usuário na linha de comando ou de forma mais permanente no ~/.ackrc
arquivo.