localiza e ecoa nomes de arquivos apenas com o padrão encontrado

9

Eu usei muito isso, a melhoria que tento conseguir é evitar nomes de arquivos de eco que não correspondam ao grep. Melhor maneira de fazer isso?

    for file in 'find . -name "*.py"'; do echo $file; grep something $file; done
    
por Gang 02.02.2017 / 13:45

6 respostas

16
find . -name '*.py' -exec grep something {} \; -print

imprimiria o nome do arquivo após as linhas correspondentes.

find . -name '*.py' -exec grep something /dev/null {} +

imprime o nome do arquivo na frente de cada linha correspondente (adicionamos /dev/null para o caso em que há apenas um arquivo correspondente, pois grep não imprime o nome do arquivo se ele for passado apenas um arquivo para procurar. A implementação GNU de grep tem uma opção -H para isso como alternativa).

find . -name '*.py' -exec grep -l something {} +

imprime apenas os nomes dos arquivos que possuem pelo menos uma linha correspondente.

Para imprimir o nome do arquivo antes das linhas correspondentes, você pode usar o 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 chame grep duas vezes para cada arquivo - embora isso seja menos eficiente, pois executaria pelo menos um comando grep e até dois para cada arquivo (e leria o conteúdo do arquivo duas vezes): / p>

find . -name '*.py' -exec grep -l something {} \; \
                    -exec grep something {} \;

Em qualquer caso, você não deseja passar o resultado de find como e Lembre-se de citar suas 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).

    
por 02.02.2017 / 14:00
6

Se você estiver usando o GNU grep, você pode usar sua opção -r ou --recursive para fazer esta simples descoberta:

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 de predicados mais avançados.

    
por 02.02.2017 / 14:17
3

Você pode dizer ao grep para incluir o nome do arquivo na saída. Então, se houver uma correspondência, ela será mostrada 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

Do 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 seus arquivos puderem ter nomes com espaços, você deverá alternar o pipe para usar os Caracteres NUL como um separador. O comando completo será agora assim:

find . -name "*.py" -print0 | xargs -0 grep -n -H something
    
por 02.02.2017 / 19:56
1

Você pode tentar algo como:

find . -name "*.py:" -exec grep -l {} \;

Este comando exec grep para cada arquivo, descoberto pelo comando find e seu recurso de comando de localização padrão

    
por 02.02.2017 / 13:56
1

Use o argumento -l .

for file in 'find . -name "*.py"'; do grep -l something $file && grep something $file; done

Um uso mais interessante seria:

for file in $(find . -name '*.py' -exec grep -l something '{}' +); do echo "$file"; grep something $file; done
    
por 02.02.2017 / 14:12
1

Existem grep alternativas que, por padrão, exibem seus resultados no formato desejado. Os dois mais populares que eu conheço são ag (ak.a. "o pesquisador de prata") 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) {
...

Eu não posso mostrar aqui, mas a saída é bem colorida. Eu obtenho os nomes dos arquivos em verde oliva, os números das linhas em amarelo ouro e a peça combinada em cada linha em vermelho sangue. As cores são personalizáveis embora.

    
por 02.02.2017 / 21:04

Tags