O Comando `grep` no Linux: Uma Ferramenta Essencial para Busca de Padrões
O comando `grep`, presente no sistema Linux, é uma ferramenta poderosa para encontrar padrões e sequências de caracteres em diversos arquivos. Ele também se integra perfeitamente com a saída de outros comandos através de pipes. Exploraremos neste artigo como usar essa funcionalidade.
A Origem do `grep`: Uma História de Necessidade e Eficiência
O `grep` é amplamente conhecido no universo Linux e Unix por três motivos principais: sua extrema utilidade, a grande quantidade de opções que podem ser intimidantes e, por fim, sua criação em tempo recorde para resolver um problema específico. Os dois primeiros pontos estão interligados, enquanto o terceiro é um fato curioso à parte.
Ken Thompson, o criador, extraiu a funcionalidade de busca por expressões regulares do editor `ed` e desenvolveu um programa simples para uso pessoal, com o intuito de realizar buscas em arquivos de texto. Seu chefe no Bell Labs, Doug Mcilroy, apresentou a Thompson o desafio de um colega, Lee McMahon, que precisava de ajuda para analisar os “Federalist Papers”.
McMahon buscava uma forma de identificar os autores dos documentos através de análises textuais, necessitando de uma ferramenta capaz de encontrar frases e padrões em arquivos de texto. Thompson dedicou uma noite para transformar sua ferramenta pessoal em um utilitário de uso geral, renomeando-o para `grep`. O nome é derivado do comando do editor `ed`, g/re/p, que significa “pesquisa global por expressão regular”.
Um vídeo de Ken Thompson conversando com Brian Kernighan sobre a criação do `grep` está disponível online para quem deseja conhecer mais da história.
Utilização Básica do `grep`
Para realizar uma busca simples por uma string em um arquivo, basta especificar o termo de busca e o nome do arquivo na linha de comando, conforme demonstrado abaixo:
grep termo_de_busca nome_do_arquivo
As linhas que contêm o termo especificado serão exibidas, com o texto correspondente destacado. Esse realce ocorre porque, em muitas distribuições Linux, o `grep` possui um alias configurado para:
alias grep='grep --color=auto'
Analisemos agora um exemplo com múltiplas linhas correspondentes. Vamos procurar pela palavra “Média” em um arquivo de log, ignorando letras maiúsculas ou minúsculas utilizando a opção -i:
grep -i Average geek-1.log
O resultado exibirá todas as linhas que contêm a palavra, com o texto correspondente realçado.
Podemos também exibir as linhas que *não* correspondem ao termo de busca utilizando a opção -v, que inverte a correspondência:
grep -v Mem geek-1.log
Nesse caso, não há realce, já que são as linhas que *não* contêm o termo pesquisado.
O comando `grep` também pode operar de forma silenciosa, sem exibir resultados na tela. O resultado da busca é passado para o shell como um código de retorno. Um código 0 indica que o termo foi encontrado, enquanto um código 1 indica que não foi. O código de retorno pode ser verificado usando o parâmetro especial `$?`:
grep -q average geek-1.log
echo $?
grep -q wdzwdz geek-1.log
echo $?
Buscas Recursivas em Diretórios
Para realizar buscas em diretórios e seus subdiretórios, utilize a opção `-r` (recursiva). É importante notar que, neste caso, você deve fornecer um caminho para o diretório em vez do nome de um arquivo. O exemplo a seguir busca no diretório atual (representado por “.”) e em seus subdiretórios:
grep -r -i memfree .
A saída incluirá o nome do diretório e do arquivo em cada linha correspondente.
Para que o `grep` siga links simbólicos, utilize a opção `-R` (recursiva com desreferência). Por exemplo, se existir um link simbólico chamado “logs-folder” apontando para “/home/dave/logs”, o uso da opção -R fará com que o `grep` também busque dentro do diretório apontado pelo link:
ls -l logs-folder
Ao repetir a busca anterior com a opção -R:
grep -R -i memfree .
O link simbólico será seguido, e o diretório alvo será pesquisado.
Busca por Palavras Inteiras
Por padrão, o `grep` irá identificar uma linha caso o termo de pesquisa apareça em qualquer parte da linha, mesmo dentro de outra palavra. Veja o exemplo ao buscar pela palavra “free”:
grep -i free geek-1.log
O resultado exibirá linhas que contêm a string “free”, que fazem parte da string “MemFree”, e não como palavras separadas.
Para forçar o `grep` a identificar apenas “palavras” separadas, use a opção `-w` (expressão regular de palavra):
grep -w -i free geek-1.log
echo $?
Nesse caso, não haverá resultados, pois o termo de busca “free” não ocorre no arquivo como uma palavra separada.
Múltiplos Termos de Busca
A opção `-E` (expressão regular estendida) permite buscar por múltiplos termos. (A opção `-E` substitui a versão obsoleta `egrep`).
O comando abaixo busca pelas palavras “média” e “memfree”:
grep -E -w -i "average|memfree" geek-1.log
Todas as linhas correspondentes serão exibidas.
Também é possível buscar por múltiplos termos que não sejam necessariamente palavras inteiras, combinando com palavras inteiras.
A opção `-e` (padrões) permite usar múltiplos termos na linha de comando, como no exemplo a seguir, onde é usada uma expressão regular para buscar por “kB” ou “KB”:
O comando irá encontrar ambas as strings. Algumas linhas conterão ambas.
Correspondência Exata de Linhas
A opção `-x` (expressão regular de linha) faz com que o `grep` identifique apenas linhas em que toda a linha corresponde ao termo de busca. No exemplo abaixo, buscamos um carimbo de data e hora:
grep -x "20-Jan--06 15:24:35" geek-1.log
A única linha correspondente é exibida.
O oposto disso é mostrar as linhas que não correspondem. Isso pode ser útil ao analisar arquivos de configuração. Os comentários são ótimos, mas às vezes é difícil identificar as configurações reais. Este é o arquivo `/etc/sudoers`:
Podemos filtrar linhas de comentários usando a opção -v:
sudo grep -v "https://www.wdzwdz.com/496056/how-to-use-the-grep-command-on-linux/#" /etc/sudoers
Isso é muito mais fácil de analisar.
Exibição do Texto Correspondente
Caso você queira visualizar apenas o texto correspondente em vez de toda a linha, use a opção `-o` (apenas correspondência), conforme demonstrado abaixo:
grep -o MemFree geek-1.log
A saída mostrará apenas o texto que corresponde ao termo de busca.
Contagem e Numeração de Linhas
O `grep` também pode fornecer informações numéricas, permitindo contar o número de vezes que um termo aparece em um arquivo utilizando a opção `-c` (contagem):
grep -c average geek-1.log
Neste exemplo, o termo de pesquisa aparece 240 vezes no arquivo.
A opção `-n` (número da linha) exibe o número da linha correspondente:
grep -n Jan geek-1.log
O número da linha é exibido no início de cada linha correspondente.
Para limitar o número de resultados exibidos, utilize a opção `-m` (contagem máxima). O exemplo abaixo limita a saída a cinco linhas correspondentes:
grep -m5 -n Jan geek-1.log
Exibição de Contexto
A habilidade de visualizar linhas adicionais, sejam elas correspondentes ou não, pode ser útil para entender o contexto das correspondências. Isso ajuda a identificar as linhas de interesse em meio a diversas correspondências.
Para exibir linhas após a linha correspondente, use a opção `-A` (após o contexto), especificando o número de linhas desejado. Por exemplo, para mostrar três linhas após cada linha correspondente:
grep -A 3 -x "20-Jan-06 15:24:35" geek-1.log
Para visualizar linhas *antes* da linha correspondente, utilize a opção `-B` (contexto anterior):
grep -B 3 -x "20-Jan-06 15:24:35" geek-1.log
E para exibir linhas tanto antes quanto depois da linha correspondente, utilize a opção `-C` (contexto):
grep -C 3 -x "20-Jan-06 15:24:35" geek-1.log
Visualização de Arquivos Correspondentes
Para visualizar os nomes dos arquivos que contêm o termo de busca, use a opção `-l` (arquivos com correspondência). Por exemplo, para verificar quais arquivos de código-fonte C contêm referências ao arquivo de cabeçalho sl.h, use o comando:
grep -l "sl.h" *.c
Os nomes dos arquivos serão listados, e não as linhas correspondentes.
A opção oposta `-L` (arquivos sem correspondência), exibe os nomes dos arquivos que *não* contêm o termo de busca:
grep -L "sl.h" *.c
Início e Fim de Linhas
O `grep` permite identificar correspondências que ocorrem no início ou no final de uma linha. O operador `^` corresponde ao início de uma linha. O exemplo abaixo busca por linhas que iniciam com um espaço:
grep "^ " geek-1.log
As linhas que iniciam com um espaço serão exibidas.
Para identificar correspondências no final da linha, utilize o operador `$`. O exemplo abaixo busca por linhas que terminam com “00”:
grep "00$" geek-1.log
As linhas que terminam com “00” serão exibidas.
`grep` com Pipes
O `grep` pode ser utilizado com pipes, permitindo que sua saída seja usada como entrada para outros comandos ou que receba a saída de outros comandos como entrada. O exemplo abaixo busca pela string “ExtractParameters” em arquivos de código fonte C, enviando a saída para o comando `less` para facilitar a visualização:
grep "ExtractParameters" *.c | less
A saída será exibida no `less`.
Isso permite que você navegue pela lista de arquivos e use o recurso de pesquisa do `less`.
Caso a saída de `grep` seja enviada para o comando `wc` (word count) com a opção `-l` (linhas), podemos contar o número de linhas que contêm “ExtractParameters” nos arquivos de código fonte:
grep "ExtractParameters" *.c | wc -l
O próximo exemplo demonstra como usar `grep` em meio a uma sequência de pipes. A saída do comando `ls -l` é enviada para `grep`, que filtra as linhas que contêm “Aug”, e a saída de `grep` é enviada para o `sort`, que ordena os resultados pelo tamanho do arquivo:
ls -l | grep "Aug" | sort +4n
Em detalhes:
- `ls -l`: Exibe uma listagem longa dos arquivos utilizando o comando `ls`.
- `grep “Aug”`: Filtra as linhas da listagem do `ls` que contêm “Aug”. Note que isso também irá identificar arquivos com “Aug” em seus nomes.
- `sort +4n`: Ordena a saída do `grep` pela quarta coluna (tamanho do arquivo).
O resultado é uma lista ordenada de todos os arquivos modificados em agosto (de qualquer ano), em ordem crescente de tamanho.
`grep`: Mais que um Comando, um Aliado
O `grep` é uma ferramenta indispensável, criada em 1974, que se mantém relevante até hoje. Sua utilidade e eficiência tornam-o uma peça fundamental no arsenal de qualquer usuário Linux.
Combinando o `grep` com expressões regulares, você pode levar suas buscas a um nível totalmente novo.