in

Usando comando Expr.

 

O comando “expr” ? muito conhecido pelos programadores
shell(bash, ksh, sh, etc.), mas, a sua utiliza??o, na
maioria das vezes, restringe-se ao comando abaixo:

contador=`expr $contador + 1`

Este comando ir? incrementar o valor da vari?vel contador
em 1, outras formas de alcan?ar o mesmo objetivo em
Bash seriam:

let contador++
contador=$((contador+1))
contador=$(bc < << "$contador + 1")

? verdade que existem v?rias outras maneiras de fazer, mas,
o foco deste documento ? apresentar as funcionalidades do
comando “expr”, um poderoso processador de express?es.

Esse comando pode ser utilizado para processar expres?es
matem?ticas atrav?s de operadores l?gicos como |, >, >=,
&, que representam o OU, E, MAIOR QUE, etc., assim como
tamb?m pode utilizar operadores aritm?ticos como visto
no exemplo acima com o operador de adi??o ou +, outros
poss?veis seriam: % ou m?dulo, * ou multiplica??o.

Abaixo veremos exemplos de express?es aritm?ticas
utilizando alguns operadores assim como os par?nteses para
agrupar e definir a ordem de execu??o dos comandos:

$ expr \( 30 + 2 \) \* \( 13 % 2 \) – \( 2 \* \( 20 – 8 \) \)
8
$ expr \( 30 + 2 \) \* \( 13 % 2 \) – \( 2 \* \( 20 – 8 \) \) / 2
20
$ expr \( \( 30 + 2 \) \* \( 13 % 2 \) – \( 2 \* \( 20 – 8 \) \) \) / 2
4

Todos sabemos que o dom?nio do t?pico “Express?es
Regulares(RegEx)” ? de grande valia e utilidade para
qualquer programador, principalmente aqueles que utilizam
linguagens scripting como Perl, PHP, Shell, Python, Ruby,
estas muitas vezes utilizadas na manipula??o de Strings.

O “expr” possui suporte ? RegEx, assim como o comando
“grep”, logo, validar express?es torna-se um trabalho
vi?vel mesmo sem o “GNU grep/egrep”, estes nem sempre
est?o dispon?veis em algumas vers?es/sabores do UNIX.

A sintaxe para o processamento de uma String ou valida??o
contra um padr?o(pattern) utilizando express?es regulares
atrav?s do comando “expr” pode ser feita de duas maneiras:

expr STRING : REGEXP

expr match STRING REGEXP

Adotaremos aqui a primeira sintaxe mostrada acima. Para
tentarmos entender como funcionam as RegEx juntamente com
o comando expr, nada melhor que exemplos, logo abaixo
seguem alguns comandos com pequenos coment?ros, alguns
deles acompanhandos do comando equivalente em utilizando o
“GNU grep”:

- Cadeias de caracteres ou Strings que come?am por “D”
precedidas ou n?o de um ou mais espa?os ou caracteres
de tabula??o(TAB)

$ expr ” Dicas” : ‘[[:blank:]]*D’
2

$ expr “Dicas” : ‘[[:blank:]]*D’
1

$ expr ” Dicas” : ‘[[:blank:]]*D’
4

Primeiramente, deve-se deixar claro que, como na maioria
dos casos no mundo UNIX, a String ? tratada de modo “Case
Sensitive”, ou seja “D” ? diferente de “d”.

O caracteres “^” que geralmente determinam o in?cio de uma
cadeia de carecteres ? impl?cito, ou seja, o “expr”, por
si s?, j? entende que o padr?o acima descrito, utilizando
a RegEx ‘[[:blank:]]*D’, ? equivalente ao utilizado atrav?s
do comando “grep”:

$ echo ” Dicas” | grep “^[[:blank:]]*D”
Dicas

O comando acima seria o equivalente ao ?ltimo comando
“expr” mostrado, veja que ele utiliza o caractere “^” para
determinar o in?cio da linha ou da cadeia de caracteres.

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 utilia??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 “)”.

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” ou “fileutils” dependendo
da distribui??o Linux, mas, que tamb?m ? encontrada na
maioria dos sistemas operacionais UNIX(testei 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 (http://guia-er.sourceforge.net/guia-er.html)