Como usar o comando “grep” para encontrar texto, incluindo subdiretórios


373

Quero encontrar todos os arquivos que contêm uma sequência específica de texto. O grepcomando funciona, mas não sei como usá-lo para todos os diretórios (só posso fazê-lo no meu diretório atual). Tentei ler man grep, mas não deu nenhuma ajuda.


grep -RIn <yor pattern> * Pesquisará nos diretórios atuais em todos os arquivos de texto. Não tenho certeza como fazer minha busca recursiva em padrões de arquivos como * .C com apenas grep

1
Curinga com a --include="*.C"opção @ user311346, graças a @Lekensteyn.
Bob Stein

Use a combinação find e grep para procurar recursivamente nos arquivos por uma string nos diretórios atual e em todos os subdiretórios. Verifique este wilddiary.com/find-files-containing-my-text
Drona

Respostas:


487

Seria melhor usar

grep -rl "string" /path

Onde

  • -r(ou --recursive) é usada para percorrer também todos os subdiretórios de /path, enquanto
  • -l(ou --files-with-matches) é usada para imprimir apenas nomes de arquivos de arquivos correspondentes, e não as linhas correspondentes (isso também pode melhorar a velocidade, dado que greppara de ler um arquivo na primeira correspondência com esta opção).

13
Na verdade, se "string" é um padrão de texto a ser encontrado, é melhor usar essa funcionalidade; caso contrário, alguém pode enfrentar problemas quando a string contiver ponto ou caractere especial que tenha significado em expressões regulares e não apenas um ponto que deverá ser encontrado como uma string , como é. Então eu usaria -rlFswitches, -Fpara "string fixa" (e não regexp - por exemplo). Claro, se a tarefa estava usando regexps, desculpe-me. Certamente, a mesma teoria sem -r também, muitas vezes vejo que as pessoas assumem o "texto" das pesquisas grep e isso pode causar problemas, os quais especiais significam algo como um regexp.
LGB

4
Há também a -ibandeira que ignora maiúsculas e minúsculas.
Marco Ceppi

3
Gostaria apenas de mostrar a --recursiveopção, existem inúmeras opções e cenários de uso sobre os quais podemos falar. Comecei a partir da resposta aceita pelo @dmityugov e modifiquei para trabalhar sem find.
enzotib

1
@NN: done :-)
enzotib

3
@ScottBiggs: com a opção--include '*.h'
enzotib 18/06

167

Se você estiver procurando por linhas correspondentes nos arquivos, meu comando favorito é:

grep -Hrn 'search term' path/to/files
  • -H faz com que o nome do arquivo seja impresso (implícito quando vários arquivos são pesquisados)
  • -r faz uma pesquisa recursiva
  • -n faz com que o número da linha seja impresso

path/to/filespode ser .procurar no diretório atual

Outras opções que eu acho muito úteis:

  • -Iignorar arquivos binários (complemento: -atratar todos os arquivos como texto)
  • -Ftratar search termcomo uma expressão literal, não regular
  • -i faça uma pesquisa que não diferencia maiúsculas de minúsculas
  • --color=alwayspara forçar as cores, mesmo durante a passagem less. Para criar lesscores de suporte, você precisa usar a -ropção:

    grep -Hrn search . | less -r
    
  • --exclude-dir=dirútil para excluir diretórios como .svne .git.

Saída de exemplo


13
-Hem uma pasta é redundante, se houver mais de um arquivo, como é provável. Na verdade, a página homem diz-H, --with-filename: Print the file name for each match. This is the default when there is more than one file to search.
enzotib

Eu não sabia disso, sempre funcionava como eu esperava. É o meu comando padrão ao procurar arquivos.
Lekensteyn

1
Existe uma maneira de considerar apenas arquivos com uma extensão, digamos, .a (e combiná-la com -r)?
precisa saber é o seguinte

6
@ user2413 Try--include '*.*'
Lekensteyn

1
@alper Trygrep --exclude='*~' ...
Lekensteyn

24

Eu acredito que você pode usar algo como isto:

find /path -type f -exec grep -l "string" {} \;

Explicação dos comentários

findé um comando que permite encontrar arquivos e outros objetos, como diretórios e links, nos subdiretórios de um determinado caminho. Se você não especificar uma máscara que os nomes de arquivos devem atender, ele enumera todos os objetos de diretório.

  • -type f especifica que ele deve processar apenas arquivos, não diretórios etc.
  • -exec grepespecifica que, para cada arquivo encontrado, ele deve executar o comando grep, passando seu nome de arquivo como argumento, substituindo {}pelo nome do arquivo

3
Apenas para quem não sabe, a adição -name '*.py'restringe as correspondências aos arquivos que terminam em '.py'.
Daniel F

Eu gosto que isso abranja clientes que não possuem -R implementado em seu comando grep.
Aviose 11/08/14

Se você deseja que a linha E o nome do arquivo correspondentes sejam impressos, faça o executor como:... -exec bash -c 'grep -r "mystring" {} && echo {}' \;
Donn Lee

qual é o desempenho relativo de apenas usar grep diretamente?
jonathan

19

Meu comando padrão é

grep -Rin string *

Eu uso um capitólio 'R' porque o lsusa para recursivo. Como o grep aceita os dois, não há razão para não usá-lo.

EDIT: por HVNSweeting, aparentemente -Rseguirá links simbólicos onde, como -rnão será.


1
Para pesquisar também em arquivos ocultos, execute shopt -s dotglob(lembre-se de -s"definir"). Tenha cuidado ao remover arquivos então. Se você ativou o dotglob, rm -r *remove tudo o que está no diretório atual, mas também o diretório acima, porque ..corresponde. Para desativar o dotglob, use shopt -u dotglob("unset"). As mudanças são temporárias, mas se aplicam apenas ao shell atual.
Lekensteyn 01/08/19

Eu esqueci disso. Existe uma maneira de configurá-lo para uma linha? algo como shopt -s dotglob & <grep cmd> & shopt -y dotglobapenas mais conveniente? Desta forma, não terá de se preocupar com redefini-lo
user606723

Além disso, é provavelmente mais fácil de usar grep -Rin string .na maioria desses casos. Eu apenas uso * porque parece vir mais naturalmente.
user606723

1
se você executar grep recursivo, poderá começar de "." ao invés de "*". nenhum dotglob necessário.
Michał Šrajer

1
votar esta, uma coisa não menciona na página de manual é Rseguirá links simbólicos, rnão
HVNSweeting

12

Se você estiver disposto a tentar algo novo, tente ack. O comando para pesquisar recursivamente o diretório atual stringé:

ack string

A instalação é bastante simples:

curl http://betterthangrep.com/ack-standalone > ~/bin/ack && chmod 0755 !#:3

(Desde que você já tenha o diretório ~/bine ele esteja de preferência no seu PATH.)


2
Ou apenas apt-get install ack-grep (e adicionar apelido ack = ack-grep ao seu .bashrc)
markijbema

O que os últimos parâmetros do chmodcomando fazem? Eles são específicos chmodou estão relacionados ao bash (a !#:3parte)?
Elliott Darfink

@ ElliottDarfink Isso está usando o recurso de histórico do Bash - !é um designador de eventos . Eles são muito poderosos para evitar repetições. !#:3referencia o terceiro token da linha de comando até o momento, ou seja ~/bin/ack, neste caso.
Konrad Rudolph

4

O comando rgrep é dedicado a essa necessidade

Se não estiver disponível, você pode obtê-lo assim

mkdir -p ~/bin
cd ~/bin
wget http://sdjf.esmartdesign.com/files/rgrep
chmod +x rgrep

Você pode definir diretamente em suas opções padrão de grep, conforme descrito acima.

Eu pessoalmente uso

[[  ${#args} -lt 5 && "${args//[[:space:]]/}" == "-i" ]] && args="-Hin"
args="${args:--Hns} --color=auto"

tópico relacionado: como sempre usar rgrep com cores


O rgrep é fornecido pelo pacote grep, que é instalado por padrão no Ubuntu.
karel

2

Atualização 2:

Esta linha de comandos usando finde grepcorrigindo o problema:

$ find path_to_search_in -type f -exec grep -in searchString {} 2> /dev/null +

--color=<always or auto> para saída colorida:

$ find path_to_search_in -type f \
            -exec grep --color=always -in searchString {} 2>/dev/null +

Exemplo:

$ find /tmp/test/ -type f -exec grep --color=auto -in "Search string" {} 2>/dev/null +

Um exemplo executado na captura instantânea abaixo: snap1


Atualização 1:

Você pode tentar seguir o código; como uma função em seu .bashrcou .bash_aliasesou em um script:

wherein () 
{ 
    for i in $(find "$1" -type f 2> /dev/null);
    do
        if grep --color=auto -i "$2" "$i" 2> /dev/null; then
            echo -e "\033[0;32mFound in: $i \033[0m\n";
        fi;
    done
}

Uso: wherein /path/to/search/in/ searchkeyword

exemplo:

$ wherein ~/Documents/ "hello world"

(Nota: Conforme sugerido nos comentários abaixo por @enzotib, isso não funciona com arquivos / diretórios, incluindo espaços em seus nomes.)


Postagem original

Para procurar a sequência e gerar apenas essa linha com a sequência de pesquisa:

$ for i in $(find /path/of/target/directory -type f); do \
    grep -i "the string to look for" "$i"; done

por exemplo:

$ for i in $(find /usr/share/applications -type f); \
    do grep -i "web browser" "$i"; done

Para exibir o nome do arquivo que contém a string de pesquisa:

$ for i in $(find /path/of/target/directory -type f); do \
    if grep -i "the string to look for" "$i" > /dev/null; then echo "$i"; fi; done;

por exemplo:

$ for i in $(find /usr/share/applications -type f); \
    do if grep -i "web browser" "$i" > /dev/null; then echo "$i"; \
    fi; done;

Falha nos nomes de arquivos que contêm espaços. A falha é ocultada pelo fato de o stderr não ser mostrado.
enzotib

@enzotib obrigado por apontar isso .. isso ainda não foi resolvido para a função especificada .. eu adicionei outro one-liner embora ..
precisa

Agora a resposta é semelhante à do @dmityugov.
enzotib

sim, mas nesse sentido a maioria das respostas nesta página, se você marcar, é similar em relação ao que elas usam grep, ao lado do subconjunto que usa findcom grep... mas se você deseja aceitar diferentes opções e ajustes como uma resposta distinta, provavelmente o meu vai caber aqui também .. ou você é diferente? a última atualização faz o que eu gostaria na minha pesquisa: nomes de arquivos com linhas com chave de pesquisa e linha não. também :) e saída colorida e filtro de erros para melhor legibilidade ..
precisa

2

grep( GNU ou BSD )

Você pode usar a grepferramenta para pesquisar recursivamente a pasta atual com o -rparâmetro, como:

grep -r "pattern" .

Nota: -r- Pesquise recursivamente subdiretórios.

Para pesquisar em arquivos específicos, você pode usar uma sintaxe invejável , como:

grep "class foo" **/*.c

Nota: Ao usar a opção globbing ( **), ele verifica todos os arquivos recursivamente com extensão ou padrão específico. Para habilitar essa sintaxe, execute: shopt -s globstar. Você também pode usar **/*.*para todos os arquivos (excluindo oculto e sem extensão) ou qualquer outro padrão.

Se você tiver o erro de que seu argumento é muito longo, considere restringir sua pesquisa ou use a findsintaxe, como:

find . -name "*.php" -execdir grep -nH --color=auto foo {} ';'

Como alternativa, use ripgrep.

ripgrep

Se você estiver trabalhando em projetos maiores ou em arquivos grandes, deve usar ripgrep, como:

rg "pattern" .

Confira os documentos, as etapas de instalação ou o código-fonte na página do projeto GitHub .

É muito mais rápido do que qualquer outra ferramenta como o GNU / BSD grep , ucg, ag, sift, ack, ptou similar, uma vez que é construído em cima do motor de regex de Rust que usa autômatos finitos, SIMD e otimizações literais agressivos para tornar a busca muito rápido.

Ele suporta padrões de ignorar especificados em .gitignorearquivos, para que um único caminho de arquivo possa ser comparado com vários padrões glob simultaneamente.


Você pode usar os parâmetros comuns, como:

  • -i - Pesquisa insensível.
  • -I - Ignore os arquivos binários.
  • -w - Pesquise as palavras inteiras (ao contrário da correspondência parcial de palavras).
  • -n - Mostre a linha do seu jogo.
  • -C/ --context(por exemplo -C5) - Aumenta o contexto, para que você veja o código ao redor.
  • --color=auto - Marque o texto correspondente.
  • -H - Exibe o nome do arquivo onde o texto é encontrado.
  • -c- Exibe contagem de linhas correspondentes. Pode ser combinado com -H.

1

Eu faço isso usando xargs, um comando muito subestimado

find ./ -type f -print0 | xargs -0 grep 'string_you_are_looking_for'

find ./ fornece uma lista recursiva de todos os arquivos em uma pasta atual e, em seguida, você o envia para o xargs que executa o comando grep em cada um desses arquivos


4
O uso de xargssem -print0opção para finde -0opção para xargsestá obsoleto, ele falhará nos nomes de arquivos que contêm espaços.
enzotib 01/08/19

@enzotib Eu editei a resposta como você sugeriu. - revise e se precisar editar e corrigir, terei prazer em reeditar por você. obrigado
αғsнιη

1
@ KasiyA: está tudo bem agora, removi meu voto negativo.
enzotib

0

Sei que há muitas respostas aqui, mas aqui está uma alternativa, se você quiser adicionar outras restrições ao pesquisar os arquivos:

find . -type f -exec grep --quiet string_to_look_for {} ';' -print

Isso funciona porque grepretornará 0 se encontrou um resultado, 1 caso contrário. Por exemplo, você pode encontrar arquivos com 1 MB de tamanho e contendo algo:

find . -type f -exec grep --quiet string_to_look_for {} ';' -size 1M -print

Para vários requisitos, você provavelmente deseja usar o sinalizador otimizador -Oque existe no GNU grep.


0

Um script (localizar no código) para pesquisar em C, código CPP:

#!/bin/sh

find . \( -iname "*.c" -o -iname "*.cpp" -o -iname "*.h" \) -type f -print0 | xargs -0 grep --color -n "$1"

Usar:

find-in-code "search string"
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.