5
Curso de Shell - Aula V Por: Alex Borro ( 24/04/2001 ) Nesta aula teremos um breve tutorial sobre o Grep. Ele não é somente um dos comandos mais úteis, mas o seu domínio abre portas para dominar outros poderosos comandos, como o sed (que trataremos na próxima aula) , awk, perl, etc. Eu fiz uma adaptação/ modificação de um tutorial que eu tenho, e por sinal é excelente, sobre o Grep e Expressões Regulares em inglês. Espero que tenha ficado legal e vocês gostem. O que ele faz? O grep basicamente faz buscas. Mais precisamente: grep palavra file retorna todas as linhas do arquivo file que contenham palavra Outro jeito de usar o grep é atraves de pipe (lembram dos pipes?). Por exemplo: ls | grep palavra Lista todos os arquivos que contenham palavra em seu nome. Ou seja, a entrada do grep é uma lista de arquivos (gerada pelo ls) que será filtrada, sendo impressas somente as linhas que contenham palavra. Usando caracteres coringas Suponho que todos saibam o que são caracteres coringas. Caso contrário, coringas são caracteres especiais que substituem outros. Geralmente o caracter "*" é um coringa que significa "qualquer caracter em qualquer quantidade". Por isso se a gente executar "ls *", onde "*" entra no lugar do "nome do arquivo", significando qualquer string de qualquer tamanho. Por isso ele lista todos os arquivos. Mas agora voltemos ao grep. Será que ele aceita coringas ??? A resposta é mais do que sim. O grep suporta algo que vai além de coringas, ele suporta Expressões Regulares. Mas vamos começar apenas com coringas. Um dos mais usados com o grep é o "." Vamos a um exemplo: >cat file >grep b.g file big big bad bug bad bug bigger bigger boogy Note que boogy não casa, desde que "." significa "qualquer e apenas um caracter". Para significar strings arbitrárias utilizamos "*", que funciona da seguinte maneira: "A expressão consistindo de um caracter seguido por um * casa com qualquer número (inclusive zero) de repetições desse caracter. Em particular, ".*" significa qualquer string." Para compreendermos vamos a mais exemplos: >cat file big bad bug bag bigger boogy>grep b.*g file big bad bug bag bigger http://olinux.uol.com.br/artigos/304/print_preview.html

Curso De Shell Aula 5

Embed Size (px)

Citation preview

Page 1: Curso De Shell   Aula 5

Curso de Shell - Aula V Por: Alex Borro ( 24/04/2001 )

Nesta aula teremos um breve tutorial sobre o Grep. Ele não é somente um dos comandos mais úteis, mas o seu domínio abre portas para dominar outros poderosos comandos, como o sed (que trataremos na próxima aula) , awk, perl, etc.

Eu fiz uma adaptação/ modificação de um tutorial que eu tenho, e por sinal é excelente, sobre o Grep e Expressões Regulares em inglês. Espero que tenha ficado legal e vocês gostem.

O que ele faz?

O grep basicamente faz buscas. Mais precisamente:

grep palavra file retorna todas as linhas do arquivo fileque contenham palavra

Outro jeito de usar o grep é atraves de pipe (lembram dos pipes?). Por exemplo:

ls | grep palavra

Lista todos os arquivos que contenham palavra em seu nome. Ou seja, a entrada do grep é uma lista de arquivos (gerada pelo ls) que será filtrada, sendo impressas somente as linhas que contenham palavra.

Usando caracteres coringas

Suponho que todos saibam o que são caracteres coringas. Caso contrário, coringas são caracteres especiais que substituem outros. Geralmente o caracter "*" é um coringa que significa "qualquer caracter em qualquer quantidade". Por isso se a gente executar "ls *", onde "*" entra no lugar do "nome do arquivo", significando qualquer string de qualquer tamanho. Por isso ele lista todos os arquivos.

Mas agora voltemos ao grep. Será que ele aceita coringas ??? A resposta é mais do que sim. O grep suporta algo que vai além de coringas, ele suporta Expressões Regulares. Mas vamos começar apenas com coringas. Um dos mais usados com o grep é o "." Vamos a um exemplo:

>cat file >grep b.gfilebig bigbad bug bad bugbigger biggerboogy

Note que boogy não casa, desde que "." significa "qualquer e apenas um caracter". Para significar strings arbitrárias utilizamos "*", que funciona da seguinte maneira:

"A expressão consistindo de um caracter seguido por um * casa com qualquer número (inclusive zero) de repetições desse caracter. Em particular, ".*" significa qualquer string."

Para compreendermos vamos a mais exemplos:

>cat file big bad bug bag bigger boogy>grep b.*g filebigbad bugbagbigger

http://olinux.uol.com.br/artigos/304/print_preview.html

Page 2: Curso De Shell   Aula 5

boogy>grep b.*g. Filebiggerboogy>grep ggg* filebigger

Avançando para expressões regulares

Os coringas são o começo, mas a idéia vai mais longe. Por exemplo, suponha que queremos uma expressão que case com Frederic Smith ou Fred Smith, ou seja, a string "eric" é opcional.

Primeiro, introduzimos o conceito de um "caracter escapado (escaped character)".

"Um caracter escapado é um caracter precedido por uma barra invertida ( \ ). Essa barra invertida faz o seguinte: (a) Remove qualquer significado especial do caracter. (b) acrescenta um significado especial a um caracter que não tenha um significado especial."

Parece complicado, mas veja nos exemplo que é um tanto quanto simples:

Para procurar uma linha contento o texto "hello.gif", o comando correto seria:

grep 'hello\.gif' file

Desde que "grep 'hello.gif' file" iria resultar linhas contendo: hello-gif , hello1gif , helloagif , etc.

Ou seja, a barra invertida remove o significado especial do ".", passando esse a significar um simples ponto ao invés de um coringa.

Agora vamos passar para expressões agrupadas, a fim de encontrar um jeito de criar uma expressão que case com Frederic ou Fred. Primeiro vamos começar com o operador "?":

"Uma expressão consistindo de caracter seguido por uma interrogação escapada ( \? ) casa com zero ou uma instância daquele caracter".

Exemplo:

"bugg\?y" casa com o seguinte: bugy , buggy mas não combugggy

neo@matrix:~$ echo bugy | grep "bugg\?y"bugyneo@matrix:~$ echo bugggy | grep "bugg\?y"neo@matrix:~$

Agora vamos para expressões agrupadas. No nosso exemplo, queremos tornar opcional a string "eric" após "Fred", ou seja, não apenas um caracter mas sim um conjunto de caracteres (string).

"Uma expressão dentro de parênteses escapados é tratada como um único caracter"

Exemplos:

"Fred\(eric\)\?" Smith casa com "Fred Smith" or "Frederic Smith"\(abc\)* casa com abc , abcabcabc, etc (isto é, qualquernúmero de repetições da string "abc", incluindozero).

Note que temos que tomar cuidado quando nossas expressões contém espaços em branco. Quando eles aparecem, precisamos colocar a expressão entre aspas, para que o shell não interprete mal nosso comando. Para o exemplo acima:

grep "Fred\(eric\)\? Smith" file

Eu aconselho fortemente a sempre usar aspas, mesmo que não usemos espaços em brancos. Já tive muita dor de cabeça porque expressões e comandos não funcionavam simplesmente por não estarem entre aspas. Um dos exemplo acima (o do bugg\?y) não funciona no meu sistema se não estiver entre

Page 3: Curso De Shell   Aula 5

aspas. Veja:

neo@matrix:~$ echo bugy | grep "bugg\?y"bugyneo@matrix:~$ echo bugy | grep bugg\?yneo@matrix:~$

Outros operadores úteis

Para casar algum caracter de uma lista, use [ ] Veja:

"[Hh]ello" casa com linhas contendo "hello" ou "Hello"

Faixas de caracteres também são permitidos:

[0-3] é o mesmo que [0123] [a-k] é o mesmo que [abcdefghijk] [A-C] é o mesmo que [ABC] [A-Ca-k] é o mesmo que [ABCabcdefghijk]

Existem também algumas formas alternativas:

[[:alpha:]] é o mesmo que [a-zA-Z] [[:upper:]] é o mesmo que [A-Z] [[:lower:]] é o mesmo que [a-z] [[:digit:]] é o mesmo que [0-9] [[:alnum:]] é o mesmo que [0-9a-zA-Z] [[:space:]] casa com qualquer quantidade de espaços,inclusive tabulações

Essas formas alternativas, como [[:digit:]] é preferível ao método direto, [0-9].

Os [ ] podem ser usado para indicar caracteres que NÃO devem estar na expressão. É só colocar o sinal ^ na primeira posição da lista. Veja:

neo@matrix:~$ echo hello | grep "[Hh]ello"helloneo@matrix:~$ echo hello | grep "[^Hh]ello"neo@matrix

Outro exemplo, um pouco mais complicado:

grep "([^()]*)a" file retorna qualquer linha contendo um par de parentes seguido por "a" e que NÃO contenham outros parênteses dentro. Assim, ele casa com essas linhas:

(hello)a(aksjdhaksj d ka)a

Mas não com: x=(y+2(x+1))a

Casando com um número especifico de repetições

Suponha que você queira casar um número específico de repetições de uma expressão. Um bom exemplo são números de telefones. Você pode procurar por um número de telefone com sete dígitos, assim:

grep "[:digit:]\{3\}[ -]\?[:digit:]\{4\}" file

Ou seja, três dígitos, opcionalmente um espaço ou um hífen e mais 4 dígitos.

Procurando por começo e fim de linha:

Isso é muito interessante. Digamos que você queira procurar por linhas que contendo espaços em brancos no começo da linha, a palavra hello e então o fim da linha. Vamos começar com este exempo:

Page 4: Curso De Shell   Aula 5

>cat file hello hello world hhello

>grep hello file hello hello world hhello

Isso não é o que nós queremos. O que está errado ? O problema é que o grep procura por linhas contendo a string hello e todas as linhas especificadas contem ela. Para contornar isso, introduzimos os caracteres de começo e fim de linha:

"O caracter ^ significa começo de linha e o $ significa fim da linha"

Retornando ao nosso exemplo:

grep "^[[:space:]]*hello[[:space:]]*$" file

Ou seja, o começo da linha, qualquer quantidade de espaço em branco (inclusive zero), a palavra hello, qualquer quantidade de espaço em branco e o fim da linha. Essa expressão faz o que a gente quer, retornando somente a linha que contém a palavra hello. Outro exemplo:

grep "^From.*Alex" /var/spool/mail/neo

Procura no meu inbox por mensagens de uma pessoa em particular (no caso, Alex). Esse tipo de expressão regular é extremamente útil e filtros de e-mail, como o procmail, utilizam isso para fazerem tudo.

Isso ou Aquilo: Procurando uma coisa OU outra:

"A expressão consistindo de duas expressões separadas pelo operador OU \| casa linhas contendo uma das duas expressões"

Note que você DEVE colocar a expressão dentro de aspas simples ou duplas:

grep "cat\|dog" file casa com linhas contendo a palavra "cat" ou apalavra "dog" grep "I am a \(cat\|dog\)" casa com linhas contendo a string "I ama cat" ou a string "I am a dog".

Usando backreference (referencia anterior)

Digamos que você queira procurar strings que contenham uma substring em mais de um lugar. Um exemplo é as tags de cabeçalhos de HTML. Suponha que eu queira procurar por "<H1>alguma string</H1>". Isto é fácil de se fazer. Mas suponha que eu queira fazer o mesmo, mas permita H2 H3 H4 H5 e H6 no lugar de H1. A expressão <H[1-6]>.*</H[1-6]> não é boa, desde que casa com "<H1>alguma string</H3>" e nos queremos que a tag de abertura seja igual a de fechamento. Para fazermos isso, usamos backreference:

"A expressão \n onde n é um número, casa com o conteúdo do n-ésimo conjunto de parênteses na expressão".

Nossa... isso realmente precisa de um exemplo!!!!

<H\([1-6]\)>.*</H\1> faz o que nos queríamos fazer acima...

"O Senhor \(dog\|cat\) e a senhora \1 foram visitar o Senhor \(dog\|cat\) e a senhora \2"

Esse é outro exemplo bobo. Os casais tem sempre que serem iguais. Ou um casal de cachorro ou de gato.

Alguns detalhes cruciais: caracteres especiais e aspas

Page 5: Curso De Shell   Aula 5

Caracteres Especiais:

Aqui nós descrevemos os caracteres especiais para RegExp (expressões regulares) no grep. Note que no "egrep", que usa expressões regulares estendidas (atualmente não tem nenhuma funcionalidade a mais que as expressões regulares normais do GNU grep), a lista de caracteres especiais são os mesmos, diferindo somente que alguns não precisar estar "escapados".

Os seguintes caracteres são considerados especiais, e precisam estar escapados:

? \ . [ ] ^ $

Note que o sinal de $ perde seu sentido se tiver caracteres depois dele, do mesmo jeito que o sinal ^ perde seu sentido se tiver caracteres antes dele. Os colchetes [ ] comportam-se um pouco diferente. A baixo segue as regras para eles:

● O colchete direito ( ] ) perde seu sentido especial se colocado no começo de uma lista, por exemplo: "[]12]" casa com ] , 1, or 2.

● Um hífen perde seu significado especial se colocado por último. Assim, [15-] casa com 1, 5 ou -

● O caracter ^ perde seu sentido se não for colocado em primeiro lugar.

● A maioria dos caracteres especiais perdem seu significado especial se forem colocados dentro de colchetes.

Aspas:

Em primeiro lugar, aspas simples são mais seguras de usar porque elas protegem suas expressões regulares de serem alteradas pelo bash (como foi visto nas aulas anteriores). Por exemplo, grep "!" file vai produzir um erro, já que o shell pensa que "!" está se referindo ao comando de histórico do shell, enquanto grep '!' file funciona perfeitamente.

Quando você deve usar aspas simples ? A resposta é: se você precisa usar variáveis do shell, use aspas duplas. Caso contrário, use aspas simples. Por exemplo:

grep "$HOME" file

Procura em file pelo nome do seu diretório pessoal, enquanto grep '$HOME' file procura pela string $HOME.

Sintaxe das expressões regulares estendidas

Agora vamos ver a sintaxe do egrep em contraste com a sintaxe do grep. Ironicamente, apesar do nome "estendido", o egrep atualmente tem menos funcionalidade do que quando foi criado, para manter a compatibilidade com o tradicional grep. A melhor maneira de fazer um grep estendido é utilizar grep -E que usa a sintaxe de expressões regulares estendidas sem perda de funcionalidade.

Bom, espero que vocês tenham tido uma boa idéia de como funcionam as expressões regulares. Elas são extremamente importante, principalmente para utilizar o grep e o poderosíssimo sed, do qual trataremos na próxima aula. Não se preocupem se estiverem confuso com as expressões, quando começarem a utilizá-las, as idéias vão clareando. Até a próxima.

Copyright (C) 1999-2000 Linux Solutions