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.507 ]

Por: Alexandre de Abreu em 16/05/2005


Exemplo prático



O exemplo a seguir é um pouco mais prático. Como retirar da String abaixo o número de identificação do processo (PID)?

# tail -1 /var/log/secure
Apr 26 09:27:01 localhost sshd[2549]: error: Address already in use.
                               ^^^^

Uma RegEx válida para esta situação seria:

'[[:upper:]][[:alpha:]]\{2\} [[:digit:]]\{2\} [:[:digit:]]\{8\} [[:alnum:]]\{1,\} [[:alnum:]]\{1,\}\[[[:digit:]]\{1,\}\]: '

Note que é possível especificar o número de ocorrências para cada representação (dígitos, alfa-numéricos, etc) indicando este número entre chaves com contra-barras: \{2\}, \{1,\}. Este último quer dizer "um ou mais".

Ao executar o comando abaixo vimos que ele retorna o número de caracteres:

$ expr "Apr 26 09:27:01 localhost sshd[2549]: error: Address already in use." : '[[:upper:]][[:alpha:]]\{2\} [[:digit:]]\{2\} [:[:digit:]]\{8\} [[:alnum:]]\{1,\} [[:alnum:]]\{1,\}\[[[:digit:]]\{1,\}\]: '
38

Mas se adicionarmos os parênteses com contra-barras na sub-cadeia que desejamos obter (PID), teremos:

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

Este documento teve por finalidade mostrar uma das funcionalidades do comando "expr" com relação a processamento de Strings, esta ferramenta, que faz parte do pacote coreutils no Linux, mas que também é encontrada na maioria dos sistemas operacionais UNIX (testado em AIX, HP-UX e SunOS/Solaris).

Lógico que para tirar o máximo desta funcionalidade é necessário um bom conhecimento sobre Expressões Regulares. Para quem ainda não tem tanto conhecimento neste tópico, segue uma fonte muito boa para estudos, este guia foi escrito pelo Aurélio Marinho:

EXPRESSÕES REGULARES
Até a próxima.

Página anterior    

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

Monitorar servidores e enviar alertas por e-mail e SMS

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

Operadores de redirecionamento

Redirecionamentos, Pipes e Fluxos

Recebendo seu IP dinâmico via email

  
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