O Linux possui muitos comandos nativos que são verdadeiros canivete-suiço para SysAdmins e criação de poderosos scripts.
Iniciei uma serie de posts sobre Shell Script, e agora irei começar a utilizar diversos comandos do Linux para tornar e dar vida a grandes funções com estes scripts, para isso, começarei a abordar separadamente os mais conhecidos e usados.
Neste post vou falar sobre o grep, muitos não sabem mas o significado do nome é (Globally Search a Regular Expression and Print), o nome já diz tudo o que esse comando faz, e deixando mais claro a ideia é procurar texto em uma string ou dentro de arquivos e mostrar linhas, ocorrências, usar combinações para pesquisar e o resultado da pesquisa ser mostrado na tela.
Você não precisa se preocupar em instalar o grep, pois ele já esta ae no seu Linux, para confirmar e verificar a versão veja o comando abaixo:
$ grep Usage: grep [OPTION]... PATTERN [FILE]... Try 'grep --help' for more information. $ grep -V grep (GNU grep) 2.16 Copyright (C) 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Written by Mike Haertel and others, see <http://git.sv.gnu.org/cgit/grep.git/tree/AUTHORS>.
Digitando apenas o comando e dando enter ele não faz nada, porém mostra um exemplo para uso, e com o parâmetro -V a versão atual, no meu caso 2.6.
Agora segue os parâmetros que iremos utilizar e suas funções:
-c | Conta quantas vezes apareceu a string que esta pesquisando |
-v | Mostra na tela “tudo” menos onde houver a ocorrência da string pesquisada |
-i | Realiza uma busca pela string ignorando o case, sendo case-insensitive |
-o | Ira mostrar na tela apenas as ocorrências da string pesquisada ignorando o resto |
-n | Ira mostrar na tela na primeira coluna a linha onde encontrou a string pesquisada |
-B | Numero de linhas a serem impressas antes da linha que contem a string pesquisada [BEFORE] |
-A | Numero de linhas a serem impressas na tela depois da encontrar a linha com a string [AFTER] |
-C | Quantidade de linhas antes e depois da linha que contem a string [CONTEXT] |
-q | Ira procurar pela string informada, porém estará em modo silencioso, nada sera impresso na tela, porém caso encontre o comando encerra com 0, caso não encontre nada será 1 |
-E | Extende o uso de Regex no padrão e combinação, usando logica AND e OR por exemplo |
-f | Um arquivo com combinações de padrões com Regex, podendo usar varias combinações |
-l | Mostra somente o nome do arquivo onde foi encontrado a string pesquisada |
-L | Semelhante ao -v, porque mostra apenas os arquivo que não contem a string informada |
-h | Pesquisa varias arquivos, diretórios se com -r mas não mostra o nome dos arquivos |
-r | Ira realizar uma pesquisa recursiva em todos os diretórios a partir do informado |
–color | Deve-se passar o parâmetro ‘never’ caso não queira que a saída marque com cor a string ou ‘auto’ e ‘always’ para operar conforme necessite. Pode mudar a cor alterando GREP_COLOR, GREP_COLORS no environment |
Exemplo básico
Agora um exemplo básico e bem didático para uso do comando, para isso vou criar um arquivo chamado palavras.txt e inserir um texto dentro e brincar com o grep.
echo -ne "amor\ncasa\nCasa\nCASA\nRaspberryPI\nRaspberry PI\nRaspberry B PI\nArduino\narduino\nARDUINO\nIDEArduino\nLinux é o poder\nEu programo Python e você?\n" > palavras.txt
Vamos visualizar nosso arquivo palavras.txt.
$ cat palavras.txt amor casa Casa CASA RaspberryPI Raspberry PI Raspberry B PI Arduino arduino ARDUINO IDEArduino Linux é o poder Eu programo Python e você?
Agora vamos usar o grep e pesquisar pela string “Raspberry“, podemos usar de duas maneiras com o cat um pipe e logo em seguida um grep ou diretamente com o comando, a primeira opção é muito utilizada, porém você irá perder performance caso realizar pesquisa em muitos arquivo ou em um arquivo longo, veremos ainda neste post sobre isso.
$ cat palavras.txt | grep "Raspberry" RaspberryPI Raspberry PI Raspberry B PI $ grep "Raspberry" palavras.txt RaspberryPI Raspberry PI Raspberry B PI
Caso eu queira contar o numero de ocorrências da string “Raspberry”:
$ grep -c "Raspberry" palavras.txt 3
Se eu quiser ver tudo menos a string que contenham “Raspberry”:
$ grep -v "Raspberry" palavras.txt amor casa Casa CASA Arduino arduino ARDUINO IDEArduino Linux é o poder Eu programo Python e você?
Agora quero pesquisar pela string “arduino”.
$ grep "arduino" palavras.txt arduino
Temos Arduino escrito de diversas maneiras, então vamos pedir para ser case-insensitive.
$ grep -i "arduino" palavras.txt Arduino arduino ARDUINO IDEArduino
E se no lugar de mostrar a linha inteira ou o que estiver junto eu mostrar apenas a string procurada.
$ grep -o "arduino" palavras.txt arduino $ grep -oi "arduino" palavras.txt Arduino arduino ARDUINO Arduino $ grep -oi "Raspberry" palavras.txt Raspberry Raspberry Raspberry
Se eu precisar saber o numero da linha onde foi encontrada a string.
$ grep -n "Raspberry" palavras.txt 5:RaspberryPI 6:Raspberry PI 7:Raspberry B PI $ grep -n "duino" palavras.txt 8:Arduino 9:arduino 11:IDEArduino
Agora vamos pesquisar pela string “arduino” e obter também as 2 linhas antes da string encontrada.
$ grep "arduino" -B 2 palavras.txt Raspberry B PI Arduino arduino
O mesmo podemos fazer obtém as linhas depois da linha com a string pesquisada.
$ grep "arduino" -A 2 palavras.txt arduino ARDUINO IDEArduino
E podemos unir as duas opções, pegando e imprimindo linhas antes e depois da linha que contem a string pesquisada.
$ grep "arduino" -C 2 palavras.txt Raspberry B PI Arduino arduino ARDUINO IDEArduino
Caso não queira mostrar nada na tela, só saber se teve sucesso ou não na pesquisa.
$ grep -q "arduino" palavras.txt $ echo $? 0 $ grep -q "Beaglebone" palavras.txt $ echo $? 1
Apenas reforçando no exemplo acima pesquisei a string “arduino” com o parâmetro -q (modo silencioso) e peguei a saída do ultimo comando executado com (echo $?), logo em seguida pesquisei por “Beaglebone” como não existe a saída foi 1.
Exemplo intermediário
Agora vamos subir um nível e brincar com outros parâmetros. Desta vez vamos criar mais 2 arquivos sistema.txt e hardware.txt, e também copiar a saída do dmesg para dmesg.log e brincar com estes caras.
Preparando os arquivos:
$ echo -ne "Linux Ubuntu\nLinux Debian\nLinux Mint\nLinux CentOS\nRaspbian\nYocto RaspberryPI\nBuildroot RaspberryPI\n" > sistema.txt $ echo -ne "ARM 1176JZF\mARM Cortex-A7\nBCM2835\nBCM2836\nBeaglebone Black\nAM3358\n" > hardware.txt $ dmesg > dmesg.log
Eu criei sistema.txt e hardware.txt com palavras aleatórias, você pode agregar mais palavras para realizar seus testes.
Agora eu quero pesquisar em qualquer arquivo e que contenha a string “Raspberry”.
$ grep "Raspberry" * palavras.txt:RaspberryPI palavras.txt:Raspberry PI palavras.txt:Raspberry B PI sistema.txt:Yocto RaspberryPI sistema.txt:Buildroot RaspberryPI $ grep "Raspberry" ./* ./palavras.txt:RaspberryPI ./palavras.txt:Raspberry PI ./palavras.txt:Raspberry B PI ./sistema.txt:Yocto RaspberryPI ./sistema.txt:Buildroot RaspberryPI
Os demais parâmetros anteriores se aplicam aqui também.
$ grep -n "Raspberry" * palavras.txt:5:RaspberryPI palavras.txt:6:Raspberry PI palavras.txt:7:Raspberry B PI sistema.txt:6:Yocto RaspberryPI sistema.txt:7:Buildroot RaspberryPI
Agora se eu criar um diretório exemplo/ e mover o palavras.txt para ele será que vai encontrar a string “Raspberry” nele ainda?
$ mkdir exemplo && mv palavras.txt exemplo/ $ grep "Raspberry" * grep: exemplo: Is a directory sistema.txt:Yocto RaspberryPI sistema.txt:Buildroot RaspberryPI
Ele avisa que existe um diretório onde esta sendo feita a pesquisa, para que ele acesse o(s) diretório(s) deve-se passar o parâmetro -r para recursividade.
$ grep -r "Raspberry" * exemplo/palavras.txt:RaspberryPI exemplo/palavras.txt:Raspberry PI exemplo/palavras.txt:Raspberry B PI sistema.txt:Yocto RaspberryPI sistema.txt:Buildroot RaspberryPI
As vezes só interessa saber a ocorrências mas não o arquivo.
$ grep -hr "Raspberry" * RaspberryPI Raspberry PI Raspberry B PI Yocto RaspberryPI Buildroot RaspberryPI
Se caso queira apenas saber qual arquivo contem a string mas não precisa mostrar ela.
$ grep -lr "Raspberry" * exemplo/palavras.txt sistema.txt
E se quiser saber os arquivos que não possuem a string pesquisada.
$ grep -Lr "Raspberry" * dmesg.log hardware.txt
Habilitando ou não o uso da saída colorida.
$ grep -r --color=always "Raspberry" * exemplo/palavras.txt:RaspberryPI exemplo/palavras.txt:Raspberry PI exemplo/palavras.txt:Raspberry B PI sistema.txt:Yocto RaspberryPI sistema.txt:Buildroot RaspberryPI $ grep -r --color=never "Raspberry" * exemplo/palavras.txt:RaspberryPI exemplo/palavras.txt:Raspberry PI exemplo/palavras.txt:Raspberry B PI sistema.txt:Yocto RaspberryPI sistema.txt:Buildroot RaspberryPI
Exemplo avançado
Vamos dar mais um passo sobre esse incrível comando, só que agora com o básico de Expressões Regulares, e como exemplo usaremos o dmesg.log gerado acima.
Fazendo uma busca simples pela string “usb”.
$ grep "usb" dmesg.log [ 0.668550] usbcore: registered new interface driver usbfs [ 0.668558] usbcore: registered new interface driver hub [ 0.668582] usbcore: registered new device driver usb [ 1.996732] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002 [ 1.996735] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1 [ 1.996737] usb usb1: Product: EHCI Host Controller [ 1.996739] usb usb1: Manufacturer: Linux 3.13.0-37-generic ehci_hcd [ 1.996741] usb usb1: SerialNumber: 0000:00:1d.0 [ 1.997338] usb usb2: New USB device found, idVendor=1d6b, idProduct=0002 [ 1.997340] usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1 [ 1.997342] usb usb2: Product: xHCI Host Controller [ 1.997344] usb usb2: Manufacturer: Linux 3.13.0-37-generic xhci_hcd [ 1.997346] usb usb2: SerialNumber: 0000:00:14.0 [ 2.000099] usb usb3: New USB device found, idVendor=1d6b, idProduct=0003 [ 2.000101] usb usb3: New USB device strings: Mfr=3, Product=2, SerialNumber=1 [ 2.000103] usb usb3: Product: xHCI Host Controller [ 2.000105] usb usb3: Manufacturer: Linux 3.13.0-37-generic xhci_hcd [ 2.000107] usb usb3: SerialNumber: 0000:00:14.0 [ 2.308561] usb 1-1: new high-speed USB device number 2 using ehci-pci [ 2.440791] usb 1-1: New USB device found, idVendor=8087, idProduct=8000 [ 2.440794] usb 1-1: New USB device strings: Mfr=0, Product=0, SerialNumber=0 [ 2.712387] usb 1-1.5: new full-speed USB device number 3 using ehci-pci [ 2.805614] usb 1-1.5: New USB device found, idVendor=0cf3, idProduct=0036 [ 2.805616] usb 1-1.5: New USB device strings: Mfr=0, Product=0, SerialNumber=0 [ 2.880293] usb 1-1.7: new high-speed USB device number 4 using ehci-pci [ 2.972951] usb 1-1.7: New USB device found, idVendor=0bda, idProduct=0129 [ 2.972954] usb 1-1.7: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [ 2.972956] usb 1-1.7: Product: USB2.0-CRW [ 2.972958] usb 1-1.7: Manufacturer: Generic [ 2.972959] usb 1-1.7: SerialNumber: 20100201396000000 [ 3.044205] usb 1-1.8: new high-speed USB device number 5 using ehci-pci [ 3.201201] usb 1-1.8: New USB device found, idVendor=0c45, idProduct=64af [ 3.201203] usb 1-1.8: New USB device strings: Mfr=2, Product=1, SerialNumber=0 [ 3.201205] usb 1-1.8: Product: Laptop_Integrated_Webcam_HD [ 3.201206] usb 1-1.8: Manufacturer: CN0Y3PX8724873AGB17FA01 [ 14.243360] usbcore: registered new interface driver btusb [ 14.274681] usbcore: registered new interface driver rts5139 [ 14.624063] input: Laptop_Integrated_Webcam_HD as /devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1.8/1-1.8:1.0/input/input13 [ 14.624169] usbcore: registered new interface driver uvcvideo [ 14.761434] usbcore: registered new interface driver ath3k [ 14.781788] usb 1-1.5: USB disconnect, device number 3 [ 14.981529] usb 1-1.5: new full-speed USB device number 6 using ehci-pci [ 20.075906] usb 1-1.5: New USB device found, idVendor=0cf3, idProduct=0036 [ 20.075911] usb 1-1.5: New USB device strings: Mfr=0, Product=0, SerialNumber=0
Bastante coisa não é? Vamos trabalhar em cima extendendo os recursos de Regex da nossa expressão, por exemplo quero somente as linhas que contenham usb2 OU usb3, aplicando a logica OR.
$ grep -E "usb2|usb3" dmesg.log [ 1.997338] usb usb2: New USB device found, idVendor=1d6b, idProduct=0002 [ 1.997340] usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1 [ 1.997342] usb usb2: Product: xHCI Host Controller [ 1.997344] usb usb2: Manufacturer: Linux 3.13.0-37-generic xhci_hcd [ 1.997346] usb usb2: SerialNumber: 0000:00:14.0 [ 2.000099] usb usb3: New USB device found, idVendor=1d6b, idProduct=0003 [ 2.000101] usb usb3: New USB device strings: Mfr=3, Product=2, SerialNumber=1 [ 2.000103] usb usb3: Product: xHCI Host Controller [ 2.000105] usb usb3: Manufacturer: Linux 3.13.0-37-generic xhci_hcd [ 2.000107] usb usb3: SerialNumber: 0000:00:14.0
Agora, vamos pesquisar por uma linha que contenha “usb” E tambem “Product:”, vamos aplicar a logica AND.
$ grep -E "usb.*Product:" dmesg.log [ 1.996737] usb usb1: Product: EHCI Host Controller [ 1.997342] usb usb2: Product: xHCI Host Controller [ 2.000103] usb usb3: Product: xHCI Host Controller [ 2.972956] usb 1-1.7: Product: USB2.0-CRW [ 3.201205] usb 1-1.8: Product: Laptop_Integrated_Webcam_HD
Mas eu quero só com “usb2” ou “usb3” casando com “Product:”.
$ grep -E "usb(2|3).*Product:" dmesg.log [ 1.997342] usb usb2: Product: xHCI Host Controller [ 2.000103] usb usb3: Product: xHCI Host Controller
Sentiu o poder da ferramenta? E você pode aplicar varias combinações com Expressões Regulares, estudaremos no futuro sobre isso.
Podemos criar um arquivo com nosso Regex e usar ele como padrão, alias, podemos colocar varias combinações neste arquivo.
$ echo "usb(2|3).*Product:" > meu_regex $ cat meu_regex usb(2|3).*Product: $ grep -f meu_regex -E dmesg.log [ 1.997342] usb usb2: Product: xHCI Host Controller [ 2.000103] usb usb3: Product: xHCI Host Controller
Usando direto e com pipe
Lembra quando comentei de usar o grep direto e usar ele com qualquer comando um pipe e logo em seguida o grep? Vamos fazer uma pesquisa no /var/log/syslog.1 por quantas ocorrências da string “info” usando cat e o grep direto.
$ time cat /var/log/syslog.1 | grep -c "info" 1027 real 0m0.011s user 0m0.005s sys 0m0.008s $ time grep -c "info" /var/log/syslog.1 1027 real 0m0.009s user 0m0.009s sys 0m0.000s
Agora uma dica legal, para desempenho de uso em grande escala do grep é setar LC_ALL=C antes:
$ strace -c grep -c "info" /var/log/syslog.1 187 % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 27.03 0.000160 11 14 mmap 14.19 0.000084 8 10 read 13.18 0.000078 13 6 open 11.15 0.000066 8 8 mprotect 9.63 0.000057 11 5 5 access 5.57 0.000033 4 9 fstat 4.56 0.000027 3 9 close 3.55 0.000021 11 2 munmap 3.55 0.000021 7 3 brk 3.04 0.000018 18 1 execve 1.52 0.000009 9 1 write 1.35 0.000008 4 2 1 ioctl 1.35 0.000008 8 1 openat 0.34 0.000002 2 1 arch_prctl ------ ----------- ----------- --------- --------- ---------------- 100.00 0.000592 72 6 total $ export LC_ALL=C $ strace -c grep -c "info" /var/log/syslog.1 187 % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 20.07 0.000114 11 10 read 16.73 0.000095 8 12 mmap 16.20 0.000092 12 8 mprotect 6.87 0.000039 8 5 5 access 6.16 0.000035 9 4 open 6.16 0.000035 18 2 munmap 5.99 0.000034 34 1 execve 5.46 0.000031 10 3 brk 4.40 0.000025 4 7 close 3.87 0.000022 3 7 fstat 2.99 0.000017 17 1 write 2.64 0.000015 15 1 openat 1.94 0.000011 6 2 1 ioctl 0.53 0.000003 3 1 arch_prctl ------ ----------- ----------- --------- --------- ---------------- 100.00 0.000568 64 6 total
Novamente verificando o tempo apos setar LC_ALL=C.
$ time grep -c "info" /var/log/syslog.1 187 real 0m0.003s user 0m0.003s sys 0m0.000s $ time cat /var/log/syslog.1 | grep -c "info" 187 real 0m0.005s user 0m0.000s sys 0m0.009s
No meu syslog.1 não deu tanta diferença, mas fazer essa varredura em um aquivo de 500M você notara uma grande diferença.
Conhecemos, aprendemos e devoramos o grep, vimos o grande potencial que ele pode nos oferecer, ainda possui mais recursos e parâmetros que não vimos e pode ser visto com man grep, mas o foco e suas principais funções foi exemplificado aqui.
Espero que tenham gostado e até a próxima!
Linux – Dominando o comando grep by Cleiton Bueno is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.