localizar e repetir nomes de arquivos apenas com o padrão encontrado

Respostas:

23
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 {} +

imprimiria o nome do arquivo na frente de cada linha correspondente (adicionamos /dev/nullo caso em que há apenas um arquivo correspondente, pois grepnão imprime o nome do arquivo se ele tiver passado apenas um arquivo para procurar. A implementação do GNU greptem uma -Hopção para isso. como uma alternativa).

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

imprimiria 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:

find . -name '*.py' -exec awk '
  FNR == 1 {filename_printed = 0}
  /something/ {
    if (!filename_printed) {
      print FILENAME
      filename_printed = 1
    }
    print
  }' {} +

Ou chame grepduas vezes para cada arquivo - embora isso seja menos eficiente, pois executaria pelo menos um grepcomando e até dois para cada arquivo (e leia o conteúdo do arquivo duas vezes):

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

De qualquer forma, você não deseja repetir a saída finddessa maneira e lembre-se de citar suas variáveis .

Se você quiser usar um loop de shell, com as 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 derivativos).

Stéphane Chazelas
fonte
6

Se você estiver usando o GNU grep, poderá usar sua opção -rou --recursivepara fazer essa busca simples:

grep -r --include '*.py' -le "$regexp" ./ # for filenames only
grep -r --include '*.py' -He "$regexp" ./ # for filenames on each match

Você só precisa findse precisar de predicados mais avançados.

Toby Speight
fonte
1
Dependendo da versão do GNU grep, greppode ou não procurar dentro de 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.
Stéphane Chazelas 2/02
5

Você pode dizer ao grep para incluir o nome do arquivo na saída. Portanto, 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

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 seus arquivos tiverem nomes com espaços, você precisará mudar o canal para usar caracteres NUL como separador. O comando completo agora ficará assim:

find . -name "*.py" -print0 | xargs -0 grep -n -H something
rollstuhlfahrer
fonte
1

Você pode tentar algo como:

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

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

Romeo Ninov
fonte
1

Use o -largumento

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

Um uso mais fácil seria:

for file in $(find . -name '*.py' -exec grep -l something '{}' +); do echo "$file"; grep something $file; done
kmkaplan
fonte
1

Existem grepalternativas que, por padrão, produzem os resultados no formato desejado. Os 2 mais populares que eu conheço são ag(também conhecido como "o pesquisador prateado") e ack. agé anunciado como uma alternativa mais rápida a 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 é bem colorida. Recebo os nomes dos arquivos em verde azeitona, os números das linhas em amarelo dourado e a peça correspondente em cada linha em vermelho sangue. As cores são personalizáveis.

JoL
fonte