Recursos avançados do bash que você não aprende na escola

Neste artigo mostro uma série de recursos disponíveis para o bash que pouca gente conhece, além de como utilizar os recursos deste programa para implementar soluções novas para o usuário.

[ Hits: 47.711 ]

Por: Leandro Santiago em 13/09/2007 | Blog: http://leandrosan.wordpress.com


Utilizando a aritmética do bash no lugar do comando test



Para quem não sabe, no bash, não é obrigatório o uso do programa test para comparação de variáveis. Digo isso pois todo mundo aprende, nos mais diversos tutoriais que encontramos na internet, a fazer comparações com o uso deste programa. Qual o problema disso?
  • Uma sintaxe diferente da que encontramos em outras linguagens.
  • Como o test é um programa externo e não um built-in do bash, sua execução é mais lenta.

O que eu pretendo com esta dica?
  • Mostrar uma sintaxe mais limpa para tais operações, a fim de tornar o código muito parecido com o mesmo código em linguagens como c/c++.
  • Tornar a execução do programa mais rápida (se bem que, como estamos falando de shell-script, isso não faz muita diferença).

Primeiramente, vou começar com o seguinte código, escrito em "shell normal":

$ i=$RANDOM
$ j=$RANDOM
$ if [ $i -eq 20 -o $j -eq 30 ]
> then
>    echo I é igual a vinte ou J é igual a 30
> fi


A mesma comparação no if poderia ser escrita com dois test's:

$ if [ $i -eq 20 ] || [ $j -eq 30 ]
> (...)


Mas, como estamos utilizando dois test's, há perda de desempenho.

Agora, o mesmo código em bash puro:

$ i=$RANDOM
$ j=$RANDOM
$ if (( ( i == 20 ) || ( i == 20 ) ))
> then
>    echo I é igual a vinte ou J é igual a 30
> fi


Ou a condição poderia ser dividida em duas operações:

$ if (( i == 20 )) || (( i == 20 ))
> (...)


Novamente, o problema da execução de mais de uma operação.

Algumas outras equivalências entre o test e o bash:

$a -lt $b <=> (( a < b ))
$a -le $b <=> (( a <= b ))
$a -gt $b <=> (( a > b ))
$a -ge $b <=> (( a >= b ))
$a -eq $b <=>(( a == b ))
$a -ne $b <=> (( a != b ))

Além desse tipo de comparação, podemos realizar tarefas como:
  • incrementar variáveis:

$ incremento=2
$ i=1
$ (( i+=incremento ))
## isso acrescenta 2 à variável i, que fica com o valor 3

O mesmo vale para operações como subtração (/), multiplicação (*) e módulo (%). Ou se você quiser, simplesmente, adicionar 1 à variável, use:

$ ((i++)) # pós-incremento
$ ((++i)) # pré-incremento
$ ((i--)) # pós-decremento
$ ((--i)) # pré-decremento

Também é possível utilizar uma atribuição "normal":

$ (( i = (j%20)+1 ))

$ ((i=i**3)) # Eleva i ao cubo

Com tudo isso e mais alguns conhecimentos de tratamento de variáveis no bash, podemos substituir os comandos -z e -n do test!

$ if (( ${#i} == 0 ))
> then
>    echo a variável i não está definida
> fi


Este comando equivale ao -z (string nula). Quanto ao -n, basta substituir o '==' por um '!='.

    Próxima página

Páginas do artigo
   1. Utilizando a aritmética do bash no lugar do comando test
   2. Manipulando bases numéricas
   3. Laços de repetição
   4. Utilizando booleanos
   5. Agradecimentos e referências
Outros artigos deste autor

Ogle: O player de DVD

Instalando um ambiente leve e funcional em computadores antigos

Assistindo vídeos no XMMS

Brincando com vetores

Alguns recursos do BASH para você utilizar em seus programas

Leitura recomendada

Discar BrasilTelecom com PPPOE no Ubuntu 6.10

Introdução a LUA, uma poderosa linguagem de programação

Dialog em GTK

Bitwise - Escovando os bits

Exemplos práticos de comandos com Parted

  
Comentários
[1] Comentário enviado por winchester em 13/09/2007 - 08:41h

WOW Valeu pelas dicas... vou anotá-las pra não esquecer!

[2] Comentário enviado por elgio em 13/09/2007 - 08:49h

Ótimo artigo. Bem oportuno.

Só não entendi direito isto:
"Novamente, o problema da execução de mais de uma operação."

Não entendi este teu problema, que tu citou com AND e OR juntos. Porque mais de uma operação? E o que ocorreu com o 'Short-circuit", técnica do C que também vale para o bash?

Short-circuit: executa só o que é necessário.
Exemplo:
if (( i == 20 )) || (( i > 100 ))

Se o i FOR 20, por causa do OU, simplesmente ele não vai fazer a comparação i>100, pois é desnecessária! Isto pode ser facilmente demonstrado em:

a)
a=20;(( a > 15 )) && (( a=0 )); echo $a
Como a foi maior que 15, "necessitou" realizar o teste no AND e o a recebeu 0.

b)
a=10;(( a > 15 )) && (( a=0 )); echo $a
Como o a NAO FOI maior que 15 (FALSO) não tem porque testar o braço do AND, pois já se sabe que toda a sentença é falsa. Logo o a permanece com 10. Isto é o short-circuit em ação!

A propósito: grandes, enormes, VIOLENTAS perdas de desempenho o pessoal acaba tendo por usar em demasia comandos externos.

[3] Comentário enviado por elgio em 13/09/2007 - 08:57h

Uma contribuição: considero o MELHOR manual de bash o "Advanced Bash Script". Acredite, é avançado mesmo. Infelizmente sem tradução.

Forte abraço

[4] Comentário enviado por Gandalfree em 13/09/2007 - 09:02h

Parabéns pelo excelente artigo, não tinha a mínima noção que fosse possível utilizar a sintaxe desta forma. Já estou até maquinando na cabeça mudar meus scripts para ficarem mais fáceis de entender por outros administradores pela familiaridade com C/C++.

Grande Abraço

[5] Comentário enviado por galmeida07 em 13/09/2007 - 10:12h

Mto bom mesmo...Obrigado! abraços

[6] Comentário enviado por tenchi em 13/09/2007 - 10:38h

Wow....
Algumas correções...

É, elgio, vc está certo... Se o primeiro comando falha o segundo nem é executado... Falha minha. Vou fazer os testes aqui para ver a diferença de desempenho. ;-)

Esqueci de falar porque é interessante especificar a base numérica de um número. Por exemplo
$ ((10==010))
$ echo $?
1

Mas se você especificar a base do segundo - na verdade de qualquer operando - como sendo decimal:
$ ((10==10#010))
$ echo $?
0

Você não tem este problema...

Ou
$ echo $((10#1+2#10+8#10))
11

Especificando a base numérica de cada um dos operadores... È confuso, mas.... ;-)


Ah, e eu acabei esquecendo... Embora eu não tivesse lido, este material já havia sido publicado, no blog do Tiago Peczenyj ( o cara manja em bash), no seguinte link:
http://peczenyj.blogspot.com/2007/07/bases-numericas-em-bash.html

Embora eu tenha descoberto o seu artigo antes de publicar aqui, acho importante deixar as coisas claras.

Ou seja,
Existem somente $((2#10)) tipos de pessoas: os que entendem binários e os que não entendem ;-) ahuahuaha
Acho que estou no segundo grupo!!!

Também há como utilizar não comente i++, i--, etc, no incremenro do for..

Por isso, coisas do tipo:
for (( i=1,j=(RANDOM%2) ; (i!=j) || (i<=10); i+=1, z=(10#$(date +%M%S)) ))
{
blee
}

São válidas, desde que façam algum sentido para o programador...

Falow, e desculpem pelos erros... Não acontecerá da próxima vez!

[7] Comentário enviado por elgio em 13/09/2007 - 13:49h

Advanced Bash Script:
http://www.tldp.org/LDP/abs/

Na boa, eu IMPRIMI o pdf e encadernei. É meu livro de bash!!

[8] Comentário enviado por tenchi em 13/09/2007 - 14:00h

ahuahau, opa Elgio...
Sobre o comentário que eu comentei que você fez, foi um num artigo sobre bash, em que você lançou um desafio sobre o comando while.. hauahua
"- Eu te desafio"
E eu não agüentei e peguei logo o meu "treis oitão".. HUAHAUHAUHA

Ah, quando à questão do desempenho dos comandos, eu pensei na seguinte possibilidade: Fora da parte aritmética do bash, cada comparação é um subprocesso, sendo assim mais lento que somente um processo composto. Mas vejo que não é bem assim. E como ainda não sou jedi suficiente - meu saber ainda dá umas piscadas ;-) - não tenho condições de analizar o código do bash para ver o funcionamento dele.


Ah, já estou lendo o seu artigo comparativo entre o desempenhos das linguagens...

Sobre as apostilas, eu já imediatamente peguei este pdf aí, que já havia visto no blog do Tiago Peczenyj, citado no comentário acima. Livrinho baum hein? Ainda bem que já tô me acostumando a ler livros técnicos em inglês (acredite, eu sou obrigado a aprender isto rsrs).

Falow.

[9] Comentário enviado por SMarcell em 13/09/2007 - 14:38h

Legal =)

A melhor maneira de se aprender qualquer coisa é FUÇANDO.

Falou!!!

[10] Comentário enviado por juliaojunior em 13/09/2007 - 14:49h

muito bom. Parabéns!!!

[11] Comentário enviado por tenchi em 13/09/2007 - 17:34h

Ah, antes que me corrijam... As operações citadas aqui são para valores inteiros... O bash não é capaz de lidar com valores reais, "pontos flutuantes". Para isso utilizem a calculadora bc.

No mais, dúvidas são bem-vindas. ;-)

[12] Comentário enviado por winchester em 13/09/2007 - 17:45h

Opa, então como vejo que você gosta de shell te mandei um email... se aceitar meu convite me avise..
Alexandre

[13] Comentário enviado por capitainkurn em 14/09/2007 - 11:09h

Excelente artigo!!!!!!
Também sou aficionado de programação e Shell script e a cada dia me deparo com mais recursos desconhecidos destes espetaculares interpretadores, especialmente o Bash.

Muito obrigado por enriquecer-nos mais com seu artigo!!!

[14] Comentário enviado por f_Candido em 16/09/2007 - 22:37h

Muito Bom. Bom mesmo. Parabéns.
Abraços

[15] Comentário enviado por tony.tux em 17/09/2007 - 08:05h

Muito interessante! Show

[16] Comentário enviado por marquinhos1875 em 24/09/2007 - 13:14h

parabens cara

[17] Comentário enviado por ftonello em 08/10/2007 - 00:59h

Muito bom! aprendi bastante coisa hehehe abraços

[18] Comentário enviado por tonybolzan em 06/12/2007 - 10:22h

Muito bom msm!!!!!!!!!

Agradeço...........

[19] Comentário enviado por GilsonDeElt em 11/06/2008 - 14:38h

Valeu, Leandro!
ficou d+ seu artigo
Achei ele enquanto procurava saber se era possível trabalhar com binário no bash (afinal, eletrônicos também trabalham com 0s e 1s =D)

E agora, para facilitar meu trabalho (e o de quem lê meus scripts), posso fazer meus bash-scripts quase como um programa C++
(já que tbm tô aprendendo C++, isso vai facilitar meu trabalho ;-)

Eu e os demais scripteiros de plantão e programadores do Bourne Again Shell agradecemos pelo artigo!
té+!

[20] Comentário enviado por wagnerfs em 29/06/2015 - 23:46h

Excelente artigo. Parabéns!
_________________________
Wagner F. de Souza
Técnico/Instrutor de Informática
"GNU/Linux for human beings."
LPI ID: LPI000297782


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner
Linux banner
Linux banner

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts