Prompt-doc: Expressões Regulares - Introdução

Aurelio Marinho Jargas
Curitiba, 17 de Dezembro de 2003



Este é o histórico da linha de comando de uma palestra que fiz para funcionários da Conectiva, sobre Expressões Regulares. O objetivo era apresentar todos os metacaracteres básicos e sua utilidade.


Os Metacaracteres

    $ #         ^ $ + * {} () | ? [] .

O arquivo de exemplo

    $ cd /etc
    $ cat passwd

Âncoras para início de fim de linha

    $ grep root passwd
    $ grep ^root passwd
    $ grep bash$ passwd
    $ grep sh$ passwd
    $ grep 'sh$' passwd          # proteger com aspas

Aspas duplas caso use variáveis

    $ zzz=ro
    $ grep "$zzzot" passwd
    $ grep "${zzz}ot" passwd     # proteger com {}

Use os colchetes para listar possibilidades para uma posição

    $ echo Carlos | grep 'Carlos'
    $ echo Carlos | grep '[Cc]arlos'
    $ echo carlos | grep '[Cc]arlos'
    $ echo harlos | grep '[Cchfg]arlos'

Misture os metacaracteres a gosto

    $ echo Carlos | grep '^[Cc]arlos$'

A lista serve para lidar com acentuação também

    $ vi /tmp/acao.txt                 # acao, ACAO, Açao, aÇãO, AÇao, etc...    
    $ cat /tmp/acao.txt | grep 'acao'
    $ cat /tmp/acao.txt | grep 'a[cç]ao'
    $ cat /tmp/acao.txt | grep 'a[cç][aã]o'
    $ cat /tmp/acao.txt | grep -i 'a[cç][aã]o'
    $ cat /tmp/acao.txt | grep '[Aa][CÇcç][AÃaã][Oo]'  # todas possibilidades

Como casar linhas em branco

    $ grep '^$' passwd

Listas negadas e intervalos

    $ grep '^[aeiou]' passwd
    $ grep '^[bcdfghjklmnpqrstvwxyz]' passwd
    $ grep '^[^aeiou]' passwd
    $ grep '[^^]' passwd             # negando o chapéuzinho
    $ grep '^[a-z]' passwd           # o hífen indica intervalo
    $ grep '^[a-]' passwd            # sem letras ao redor, hífen normal
    $ grep '^[-z]' passwd
    $ grep '^[az-]' passwd
    $ grep '^[0-9]' passwd           # linhas iniciadas por números
    $ grep '[0-9]' passwd
    $ grep '[0-90-9]' passwd         # errado
    $ grep '[0-9][0-9]' passwd       # certo
    $ grep '[0-9][0-9][0-9]' passwd

Intervalos respeitam a tabela ASCII

    $ man ascii

Classes POSIX respeitam o LOCALE

    $ echo ááá | grep '[a-z]'
    $ echo $LANG
    $ echo ááá | grep '[[:lower:]]'
    $ echo ááá | grep '[0-9[:lower:]ABC ]'

O curinga: o ponto

    $ grep '^[aeiou]' passwd         # começa com vogal
    $ grep '^.[aeiou]' passwd        # segunda letra vogal
    $ grep '^..[aeiou]' passwd       # terceira letra vogal

Egrep e chaves para repetições

    $ grep '^.......................[aeiou]' passwd
    $ grep '^.{25}[aeiou]' passwd     # errado
    $ grep '^.{5}[aeiou]' passwd      # errado
    $ grep '^.\{5\}[aeiou]' passwd    # deve escapar!
    $ egrep '^.{5}[aeiou]' passwd     # ou usar o egrep
    $ egrep 'f{995}' passwd           # 995 efes
    $ egrep 'f{1,995}' passwd         # de 1 a 995 efes

Mais sobre chaves

    $ egrep '^.{5}[aeiou]' passwd      # sexta letra vogal
    $ egrep '^.{4,5}[aeiou]' passwd    # quinta ou sexta letra vogal
    $ egrep '^.{1,5}[aeiou]' passwd    # de segunda a sexta letra vogal
    $ egrep '^.{5,}[aeiou]' passwd     # sexta (ou mais) vogal

Linhas de tamanho fixo

    $ echo aaaaaaaaaaaaaaaa | egrep 'a{6}'
    $ echo aaaaaaaaaaaaaaaa | egrep '^a{6}$'
    $ echo aaaaaaaaaaaaaaaa | egrep '^a{6,}$'
    $ echo aaaaaaaaaaaaaaaa | egrep 'a{6,}'
    $ echo aaaaaaaaaaaaaaaa | egrep 'a{2,6}'

Repetição de listas

    $ egrep '[aeiou]{2}' passwd        # duas vogais seguidas
    $ egrep '^.[aeiou]{2}' passwd      # segunda e terceira vogais

? * e + são atalhos para as chaves {}

    $ #       ?  {0,1}        *  {0,}      +  {1,}

O opcional ?

    $ echo mala | egrep mala
    $ echo malas | egrep malas?
    $ echo mala | egrep malas?
    $ echo mala | egrep mal(as)?           # erro!
    $ echo mala | egrep 'mal(as)?'         # deve proteger com 'aspas'
    $ echo mal | egrep 'mal(as)?'

Não há como negar strings no meio da linha

    $ echo mala | egrep '[^l][^a]'
    $ echo mala | egrep '(^la)'
    $ echo mala | egrep '(^ma)'

Grupos são legais!

    $ echo mala | egrep '(((((((((a)))))))))'
    $ echo mala | egrep '((((((((((a))))))))))'
    $ echo mala | egrep '((((((((((a)))))))))'
    $ echo mala | grep '\(\(\(\(\(\(\(\(\(\(a\)\)\)\)\)\)\)\)\)\)'

Os retrovisores (máximo de nove, marca o texto e não a ER)

    $ echo mala | egrep '(a)l\1'
    $ echo aja | egrep '(a).\1'
    $ echo a.a | egrep '(a).\1'
    $ echo a.a | egrep '([0-9]).\1'
    $ echo 7a7 | egrep '([0-9]).\1'
    $ echo 788 | egrep '([0-9])\1\1'      # não casa
    $ echo 888 | egrep '([0-9])\1\1'      # casa
    $ echo 888 | egrep '([0-9])\1{2}'     # casa

Como procurar palavras repetidas

    $ echo "por que que eu sou" | egrep '([a-z]{2,8}) \1'
    $ echo "por que qu eu sou" | egrep '([a-z]{2,8}) \1'
    $ echo "quero-quero" | egrep '([a-z]{2,8})-\1'

Usando ? * e +

    $ echo b | egrep 'a*'
    $ echo b | egrep 'a+'
    $ echo b | egrep 'a?'
    $ echo ab | egrep 'a+'
    $ echo aaaaaa | egrep 'a+'
    $ echo aaaaaa | egrep '^a+$'
    $ echo aaaaaa | egrep '^a*$'

O tudo e o nada: ponto-asterisco .*

    $ echo aaaaaa | egrep '.*'
    $ echo | egrep '.*'
    $ echo dayukafukdfkidrifhiioyohgoyiejeoueou | egrep '.*'

? * e + são gulosos!

    $ echo "antes <b>bold<i>ital</i></b> texto" | sed 's/<.*>//g'
    $ echo "antes <b>bold<i>ital</i></b> texto" | sed 's/<.\{0,\}>//g'
    $ echo "antes <b>bold<i>ital</i></b> texto" | sed 's/<.\{1,\}>//g'
    $ echo "antes <b>bold<i>ital</i></b> texto" | sed 's/<.\{2,\}>//g'
    $ echo "antes <b>bold<i>ital</i></b> texto" | sed 's/<.\{2\}>//g'
    $ echo "antes <b>bold<i>ital</i></b> texto" | sed 's/<.\{1,2\}>//g'
    $ echo "antes <b>bold<i>ital</i></b> texto" | sed 's/<[^>]*>//g'

Ou isso ou aquilo

    $ egrep 'root|ftp' passwd
    $ egrep '^root|FTP' passwd
    $ egrep '^(root|FTP)' passwd
    $ egrep '^(root|ftp)' passwd
    $ egrep '^(root|ftp).*\1' passwd

Procurar por palavras repetidas na mesma linha

    $ cat passwd | egrep '(mail).*\1.*\1'
    $ cat passwd | egrep '([a-z]{3,}).*\1.*\1'
    $ cat passwd | egrep '^([a-z]{3,}).*\1.*\1'
    $ cat passwd | egrep '^([a-z]{3,}).*/home/\1'
    $ cat passwd | egrep '^([a-z]{3,}).*/var/spool/\1'

Usuários com shell e que o $HOME é diferente do login

    $ cat passwd | egrep 'bash$' | egrep -v '^([a-z]{3,}).*/var/spool/\1'
    $ cat passwd | egrep 'bash$' | egrep -v '^([a-z]{3,}).*/home/\1'

Ou isso ou aquilo também se aplica a ERs complicadas!

    $ cat passwd | egrep '^[aeiou]{2}|bash$'
    $ cat passwd | egrep '(^[aeiou]{2})|(bash$)'
    $ cat passwd | sed -nr 's/((^[aeiou]{2})|(bash$))/XXXX/gp'

Uma ER bem simples para casar um email

    $ #         [A-Za-z0-9._]+@([A-Za-z0-9-]+\.)+[A-Za-z]{2,6}

Trocando a ordem de campos

    $ grep root passwd | cut -d: -f1,6
    $ grep root passwd | cut -d: -f1,6 | sed -r 's/(.*):(.*)/\2:\1/'

Voltar para a página dos cursos na Conectiva