Utilizando "expr" para "String Matching" através de expressões regulares em shell

Este artigo tem por intuito mostrar mais uma técnica de "String Matching" em shell tirando proveito de RegEx através do comando "expr". Este comando é encontrado na maioria dos sistemas operacionais UNIX, o que facilita o desenvolvimento em plataformas sem ferramentas GNU instaladas. No Linux, o comando faz parte do pacote "coreutils".

[ Hits: 31.218 ]

Por: Alexandre de Abreu em 16/05/2005


Como validar expressões



Voltando ao comando:

$ expr " Dicas" : '[[:blank:]]*D'

Verificamos que a saída padrão é igual a 4, pois de acordo com a String que foi testada contra o padrão em RegEx acima existem 4 caracteres que estão de acordo com a cadeia " Dicas": 3 espaços e o caracter "D".

O "expr" imprime na saída padrão o número de caracteres que estão de acordo com o padrão testado, no último caso, 4. Veremos logo abaixo como imprimir os caracteres que estão de acordo com o padrão especificado na linha de comando, o que é bem mais interessante e útil.

Vejam que a String " Dicas" está entre aspas duplas e não entre aspas simples. É interessante sempre adotar este procedimento, pois ao utilizar variáveis, o valor da variável é utilizado durante a expressão:

$ STR="   Dicas"
$ expr "$STR" : '[[:blank:]]*D'

4

Como validar uma expressão?

Qual seria o comando "expr" para validar uma String que pode ser resultado de uma entrada de usuário utilizando o "read", uma linha de um arquivo ou saída padrão de um comando? Utilizando "grep", teremos:

$ STR="localhost.localdomain"
$ echo "$STR" | grep -q "localhost" && echo OK

OK

$ if grep -q "localhost" /etc/hosts; then
  echo "Existe"
else
  echo "Não existe"
fi


Estes exemplos são bem simples, o parâmetro "-q" do comando "grep" suprime a saída padrão. O Bash ainda possibilita a utilização da forma abaixo para "Pattern Matching":

$ STR="localhost.localdomain"
$ [[ $STR = l* ]] && echo OK

OK

Mas, ainda assim não será suficiente para alguns casos, como veremos a seguir. Um exemplo mais interessante seria a validação de um nome de diretório/arquivo ou uma String em relação ao padrão resultante do comando "date" abaixo:

$ date '+%d%m%y-%T'
260405-11:52:52

O expr pode ser empregado nesta situação. Abaixo veremos que a representação "[[:digit:]]" equivale aos números de 0 a 9 ou "[0-9]". Vejamos como seria o comando correto para validação:

$ STR=`date '+%d%m%y-%T'`
$ expr "$STR" : '[[:digit:]]\{6\}-[[:digit:]]\{2\}:[[:digit:]]\{2\}:[[:digit:]]\{2\}'

15
$ echo $?
0

Como vimos, o comando "expr" acima retorna 0, ou seja, quando há um "matching" ele retorna "true" ou verdadeiro: variável $? igual a 0. O valor de retorno pode ser armazenado em uma variável e posteriormente verificado através dos comandos abaixo:

$ STR="Dicas-Linux eh legal"
$ expr "$STR" : '.*Linux.*' > /dev/null

$ if [ $? -eq 0 ]; then
  echo "Encontrado"
else
  echo "Nada encontrado"
fi


O padrão acima corresponde a qualquer cadeia que contenha a palavra "Linux". O caractere "." equivale a qualquer caractere. O retorno será verdadeiro, logo, será mostrado na tela a palavra "Encontrado".

Como retornar a cadeia que está de acordo com o padrão especificado? Resposta: Utilizando parênteses. Vamos a um exemplo simples, mostrando o comando utilizado no começo deste documento:

$ expr "   Dicas" : '\([[:blank:]]*D\)'
   D

Este comando retorna os caracteres da String que estão de acordo com o padrão especificado através da RegEx e demarcados pelos parênteses. Note que os parênteses devem ser "escapados" com contra-barras para que não sejam entendidos como um caractere literal "(" ou ")".

Página anterior     Próxima página

Páginas do artigo
   1. Introdução
   2. Utilizando expressões regulares
   3. Como validar expressões
   4. Exemplo prático
Outros artigos deste autor
Nenhum artigo encontrado.
Leitura recomendada

Definição automática de wallpaper em função do horário

Redirecionamentos, Pipes e Fluxos

Operadores de redirecionamento

Recebendo seu IP dinâmico via email

Expressões regulares no Bash : parte I

  
Comentários
[1] Comentário enviado por fabio em 16/05/2005 - 23:27h

Belo artigo! Bom, analisando o padrão do exemplo da página 4, aí vai uma expr um pouco mais simples para se extrair o PID do processo:

expr "Apr 26 09:27:01 localhost sshd[2549]: error: Address already in use." : '.*\[\([[:digit:]]\{1,\}\)\]'

O entendimento da mesma fica como dever de casa :P

[]'s,
Fábio

[2] Comentário enviado por inode em 16/05/2005 - 23:34h

Olá Fábio,

O objetivo não é conseguir a informação de maneira mais fácil e sim de maneira mais segura e confiável. Veja que sua regex gera falso-positivos. Um exemplo:

expr "Apr 26 09:27:01 localhost sshd[2549]: error [4567]: Address already in use." : '.*\[\([[:digit:]]\{1,\}\)\]'
4567

:)

[]s

Alexandre de Abreu

[3] Comentário enviado por fabio em 17/05/2005 - 00:26h

Opa,

Mas na linha de log que você mostrou não há exemplo de duas ocorrências de par de chaves []. Uma expressão regular é construída a partir da análise de um padrão e o padrão que segui foi o citado no artigo.

Além do mais, em artigos introdutórios como o seu, devemos sempre priorizar os comandos mais simples para deixar o texto mais didático. Aposto cinco mangos contigo que 90% dos que lerem esse artigo e não forem experts em expressões regulares vão custar ou não vão entender bulúfas da página 4.

Conclusão, era mais fácil concordar que minha regex é uma alternativa resumida à sua :)

[]'s,
Fábio

[4] Comentário enviado por inode em 17/05/2005 - 01:13h

Fábio,

Abra uma sessão: Tópicos Avançaos em Shell com Expressões Regulares, coloque o artigo lá ou ainda, deixe claro que os artigos não podem ser direcionados a usuários que não sejam "experts" como você falou e assim ficamos em paz. :)

Se vamos discutir isso, que seja dito a verdade, a expressão regular para tal tarefa é a descrita no artigo, ele valida uma entrada com o padrão:

^Mes Dia HH:MM:SS Hostname software[PID] Qualquercoisa/Whatever

Escrevi o artigo no intuito de mostrar uma ferramenta e não descrever o tópico RegEx, além disso, não julgo o artigo como introdutório em lugar algum.

Valeu

Alexandre


[5] Comentário enviado por fabio em 17/05/2005 - 02:45h

Mas então, quando buscamos criar uma expressão regular, o objetivo é sempre chegar a mais simples e resumida possível. Analisando sua entrada com o padrão:

^Mes Dia HH:MM:SS Hostname software[PID] Qualquercoisa/Whatever

Podemos concluir que a informação desejada é a única que está entre colchetes. Daí o surgimento de uma expressão que busca somente as informações dentre os próprios colchetes. Não é necessário fazer a expressão "casar" com o resto do padrão se este resto não nos interessa.

Se na aula de história você vai falar sobre o homo-sapiens, não precisa falar sobre o ?homo-herectus? para o professor ou a turma entender o que é homo-sapiens. hehehe

Sua regexp está certa e completa, mas estou, através dos comentários, mostrando que nesse assunto temos diversas formas para chegarmos a um resultado final. Você respondeu como se fosse o dono da verdade, morfando o padrão da linha para uma situação imaginária só pra dizer que minha sugestão estava incorreta, mas não é por aí. Notei que sua personalidade era assim nos e-mails que me enviou antes e depois do artigo ser publicado... bom, mas isso é assunto nosso, deixa pra lá!


[]'s,
Fábio

[6] Comentário enviado por inode em 17/05/2005 - 09:59h

Cara, que comédia, eu tento mostrar algo interessante no artigo sobre expr ai vem você criticar uma simples RegEx. Que infelicidade a minha! :)

Não sou dono da verdade Fábio, mas, se é para mostrar algo, que seja mostrado da forma correta. Você tem muito que aprender ainda sobre RegEx, um dia saberá que um falso-positivo acaba com seu sistema e que o importante é segurança e confiabilidade, e não fazer a RegEx mais simples possível. Iss cabe um novo artigo, não?

Para acabar com a discussão: sua RegEx funciona! Ela retorna o último número entre colchetes, é isso que quer ler?

Bom dia! ;)

[7] Comentário enviado por lyma em 17/05/2005 - 11:48h

Gostaria de interromper esta produtiva discussão para parabenizar sobre o ótimo artigo.

Um abraço aos dois! :)

[8] Comentário enviado por inode em 17/05/2005 - 12:55h

Valeu lyma, qualquer dúvida manda ai. :)

[9] Comentário enviado por agk em 02/06/2005 - 14:51h

Bastante interessante o artigo, mas para entendê-lo melhor teria que me aprofundar um pouco mais em Shell Script como diz no final do artigo.

[10] Comentário enviado por agressiveinlinux em 18/08/2010 - 15:16h

Pessoal não sei se minha dúvida é sobre o assunto, mas lá vai, estou precisando saber qual comando uso para encontrar caracteres ascii em um texto, já tentei usar o find mais nada, o grep dá algum suporte ou vocês sabem de outro comando para fazer isso.

Obrigado!!


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts