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".
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:
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:
$ 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 ")".
[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:
[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 :)
[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.
[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á!
[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?
[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.