Usei muito isso, a melhoria que tento alcançar é evitar ecoar nomes de arquivo que não correspondam em grep. Melhor maneira de fazer isso?
for file in `find . -name "*.py"`; do echo $file; grep something $file; done
Comentários
- Relacionados (em Pergunte ao Ubuntu ): Pesquisar recursivamente um padrão / texto apenas no nome de arquivo especificado de um diretório?
Resposta
find . -name "*.py" -exec grep something {} \; -print
imprimiria o nome do arquivo depois das linhas correspondentes.
find . -name "*.py" -exec grep something /dev/null {} +
imprimiria o nome do arquivo na frente de cada linha correspondente (adicionamos /dev/null
para o caso em que há apenas um arquivo correspondente como grep
não imprime o nome do arquivo se for passado apenas um arquivo para consulta. A implementação GNU de grep
tem uma -H
opção para isso como alternativa).
find . -name "*.py" -exec grep -l something {} +
imprimiria apenas os nomes dos arquivos que têm pelo menos uma linha correspondente.
Para imprimir o nome do arquivo antes das linhas correspondentes, você poderia usar awk em vez disso:
find . -name "*.py" -exec awk " FNR == 1 {filename_printed = 0} /something/ { if (!filename_printed) { print FILENAME filename_printed = 1 } print }" {} +
Ou ligue para grep
duas vezes para cada arquivo – embora “d seja menos eficiente, pois executaria pelo menos um comando grep
e até dois para cada arquivo (e ler o conteúdo do arquivo duas vezes ):
find . -name "*.py" -exec grep -l something {} \; \ -exec grep something {} \;
Em qualquer caso, você não deseja fazer um loop sobre a saída de find
assim e lembre-se de citar seu variáveis .
Se você quiser usar um loop de shell, com ferramentas GNU:
find . -name "*.py" -exec grep -l --null something {} + | xargs -r0 sh -c " for file do printf "%s\n" "$file" grep something < "$file" done" sh
(também funciona no FreeBSD e derivados).
Resposta
I se estiver usando GNU grep, você pode usar a opção -r
ou --recursive
para fazer esta busca simples para você:
grep -r --include "*.py" -le "$regexp" ./ # for filenames only grep -r --include "*.py" -He "$regexp" ./ # for filenames on each match
Você só precisa de find
se precisar predicados mais avançados.
Comentários
- Dependendo da versão do GNU
grep
,grep
pode ou não olhar dentro dos links simbólicos ou atravessar links simbólicos para diretórios. Você também pode encontrar algumas variações no tratamento de outros tipos de arquivos não regulares.
Resposta
Você pode dizer ao grep para incluir o nome do arquivo na saída. Portanto, se houver uma correspondência, ela será exibida no console; se não houver correspondência em um arquivo, nenhuma linha será impressa para esse arquivo.
find . -name "*.py" | xargs grep -n -H something
De man grep
:
-H Always print filename headers with output lines -n, --line-number Each output line is preceded by its relative line number in the file, starting at line 1. The line number counter is reset for each file processed. This option is ignored if -c, -L, -l, or -q is specified.
Se os seus arquivos podem ter nomes com espaços, você deve mudar o tubo para usar caracteres NUL como separador. O comando completo ficará assim:
find . -name "*.py" -print0 | xargs -0 grep -n -H something
Resposta
Você pode tente algo como:
find . -name "*.py:" -exec grep -l {} \;
Este comando exec grep para cada arquivo, descoberto pelo comando find e seu recurso padrão find command
Resposta
Use o argumento -l
.
for file in `find . -name "*.py"`; do grep -l something $file && grep something $file; done
Um uso mais findish seria:
for file in $(find . -name "*.py" -exec grep -l something "{}" +); do echo "$file"; grep something $file; done
Resposta
Lá são grep
alternativas que, por padrão, exibem seus resultados no formato desejado. Os 2 mais populares que conheço são ag
(a.k.a. “the silver searcher”) e ack
. ag
é anunciado como uma alternativa mais rápida para ack
.
$ ag "^\w+\s*\w+\(" ~/build/i3/src build/i3/src/display_version.c 58:void display_running_version(void) { build/i3/src/load_layout.c 42:static TAILQ_HEAD(focus_mappings_head, focus_mapping) focus_mappings = 518:json_content_t json_determine_content(const char *filename) { 575:void tree_append_json(Con *con, const char *filename, char **errormsg) { build/i3/src/x.c 64:CIRCLEQ_HEAD(state_head, con_state) state_head = 67:CIRCLEQ_HEAD(old_state_head, con_state) old_state_head = 70:TAILQ_HEAD(initial_mapping_head, con_state) initial_mapping_head = 97:void x_con_init(Con *con, uint16_t depth) { ...
Não posso mostrar aqui, mas a saída está perfeitamente colorida. Recebo os nomes dos arquivos em verde oliva, os números das linhas em amarelo dourado e a peça correspondente em cada linha em vermelho sangue. No entanto, as cores são personalizáveis.