Brincando com vetores

Não, não vou falar de como combater o mosquito da dengue. Vou falar um pouco de vetores, que até há algum tempo atrás eu nem sabia que existiam em shell. Espero que vocês fiquem tão impressionados quanto fiquei!

[ Hits: 70.063 ]

Por: Leandro Santiago em 23/01/2007 | Blog: http://leandrosan.wordpress.com


Matemática e lógica com elementos de um vetor



Podemos usar aqueles truques de lógica e matemática (>,<,&&,&,||,++,--,etc) com elementos de um vetor também.

Exemplos:

Primeiro, criaremos um vetor com elementos numéricos:

$ SEQ=($(seq 0 2 10)) # Seis primeiros pares
$ echo ${SEQ[@]}
0 2 4 6 8 10

Agora, por exemplo, incrementamos o elemento SEQ[4]:

$ ((SEQ[4]++))

E atribuímos o valor SEQ[1]**3 ("ao cubo") ao elemento SEQ[1]:

$ ((SEQ[1]=SEQ[1]**3))

Exibindo o vetor:

$ echo ${SEQ[@]}
0 8 4 6 9 10

Somando dois elementos de um vetor:

$ Soma=$((SEQ[1]+SEQ[2]))

Usando condicionais:

Se o primeiro elemento de SEQ é zero:

$ ((SEQ==0)) && echo ${SEQ} é igual a zero
0 é igual a zero

Se o elemento de índice 4 de SEQ é positivo (ou menor que zero):

$ ((SEQ[4]>=0)) && echo ${SEQ[4]} é positivo || echo ${SEQ[4]} é negativo
9 é positivo

Um exemplo prático:

#!/bin/bash
# Script que diz quantos números negativos, positivos e neutros há num vetor
vetor=(-1 -5 5 6 -10 3 8 9 0) # Inicializo o vetor
# Inicializo algumas variáveis
negativo=0
positivo=0
neutro=0
Tamanho=${#vetor[@]} # Tamanho guarda o número de elementos de "vetor"
for ((i=0;i<Tamanho;i++))
do
   if ((vetor[i]>0)); then ((positivo++))
   elif ((vetor[i]<0)); then ((negativo++))
   else ((neutro++)); fi
done
echo "Em vetor existem $positivo números positivos, $negativo negativos e $neutro neutros."

Executando, teremos a seguinte saída na tela.

Em vetor existem 5 números positivos, 3 negativos e 1 neutros.

Estes foram somente exemplos mais simples. Há muito mais recursos lógico-aritméticos que podem ser usados em shell script. Há, inclusive, muitos artigos e dicas muito bons aqui mesmo no VOL que ensinam a usar estes recursos.

Página anterior     Próxima página

Páginas do artigo
   1. Operações básicas com vetores
   2. Matemática e lógica com elementos de um vetor
   3. Vetores como argumento de uma função
   4. Considerações finais
Outros artigos deste autor

Mudando o tema dos cursores do mouse no Linux

Ogle: O player de DVD

Assistindo vídeos no XMMS

Brincando com vetores - complemento

Instalando um ambiente leve e funcional em computadores antigos

Leitura recomendada

Hdparm - Entendendo seu funcionamento e criando um script para Slackware

Criando Arrays, Arrays Multidimensionais e Hashes em BASH Script

Aviso de queda de Internet via Sendxmpp

Reconhecimento de Voz no Linux

Alternância de GPU em notebooks Core-i

  
Comentários
[1] Comentário enviado por tenchi em 23/01/2007 - 10:28h

Ae pessoal, eu esqueci de falar que, para que as operações funcionem corretamente, é preferível que os elementos do vetor não contenham o caractere espaço ' '.
Mas como isso pode ser feito? Basicamente substituindo o espaço por um caractere, como o underline (_).
Por exemplo, se os elementos de um vetor forem lidos pelo usuário:

(...)
indice=0
while <alguma coisa>
do
read elemento
vetor[$indice]=`echo $elemento | tr ' ' '_'`
let indice++
done
(...)

Assim, a string "O rato roeu a roupa" estará dentro do vetor da seguinte forma: "O_rato_roeu_a_roupa".
E quando formos ler o valor de um elemento, fazemos o seguinte:
echo ${vetor[$i]} | tr '_' ' '

Bem, espero que não se incomodem pela minha falta de atenção, pois sem esse negócio de substituir o espaço, um elemento "alguma coisa" logo viraria dois elementos: "alguma" e "coisa", o que seria um erro brutal.

E para passar um vetor por referencia, usamos o comando eval, que é muito útil.
Com ele, nos referirmos à um vetor não como ${vetor1[@]}, mas como vetor1 somente, o que acaba com aquele desperdício de processamento que eu comentei. Por exemplo, vou reescrever as funções Invert e quant que citei acima:


Invert()
{
eval 'Tamanho=${#'$1'[@]}'
eval 'for ((i=0;i<(Tamanho/2);i++))
do
x=${'$1'[$i]}
'$1'[$i]=${'$1'[((Tamanho-i))]}
'$1'[((Tamanho-i))]=$x
done'

}

function quant
{
local negativo=0
local positivo=0
local neutro=0
eval 'local Tamanho=${#'$1'[@]}'
eval 'for ((i=0;i<Tamanho;i++))
do
if (('$1'[i]>0)); then ((positivo++))
elif (('$1'[i]<0)); then ((negativo++))
else ((neutro++)); fi
done'
echo "$negativo:$neutro:$positivo"
}

Usando:
$ Nomes=(ana beto carlos daniel)
$ echo ${Nomes[@]}
ana beto carlos daniel
$ Invert Nomes
$ echo ${Nomes[@]}
daniel carlos beto ana

$ Numeros=( 5 6 10 -20 -60 0 0 0 5 30)
$ quant Numeros
2:3:5

Sei que assim as coisas ficam bem confusas, mas eu ainda estou procurando um jeito de melhorar isso tudo. E uma hora ou outra as coisas ficam confusas, não é?

Me desculpem mesmo pela falta de atenção.

Falow.

[2] Comentário enviado por dailson em 23/01/2007 - 13:01h

Rapaz....
Esse artigo deve entrar para a galera dos artigos mais úteis aqui do VOL
Parabéns cara!!!

[3] Comentário enviado por bryan em 23/01/2007 - 14:26h

Muito bom o artigo, gostei...
Deixa ainda mais completo o acervo de tutoriais sobre Shell Script aqui no VOL. =]

Bryan

[4] Comentário enviado por dailson em 23/01/2007 - 16:02h

Aproveitando o artigo de vetores, alguém sabe informar porque a variável $STRING no laço não funciona... ou melhor, ela é carregad, mas o sed não faz o que deveria fazer??

PALAVRAS=("google" "googleadservices" "atdmt")
TAMANHO_VETOR=`echo ${PALAVRAS[*]} | wc -w`
# Subtraio uma posicao do tamanho, pois o vetor começa na posicao 0 (zero)
let TAMANHO_VETOR--

# Limpeza
for i in `seq 0 $TAMANHO_VETOR`
do
STRING=`echo ${PALAVRAS[$i]}`
sed -n '/$STRING/!p' /etc/squid/hosts.txt > /etc/squid/hosts.txt.temp
mv /etc/squid/hosts.txt.temp /etc/squid/hosts.txt
done

[5] Comentário enviado por tenchi em 23/01/2007 - 16:55h

Hum... dailson, primeiramente, valew pelos comentários...
Segundo, acho que o seu sed não está funcionando pois o nome $STRING não está sendo substituido pelo conteúdo dele. Por causa das aspas simples...
Tente usar as aspas duplas..

Ou depure o seu script.
Faça o seguinte:
$ bash -xv script.sh

Assim é possível ver aonde está o erro.
Acredite, esse negócio de depurar programas é uma tremenda mão na roda.
Veja a saída do comando que vc vai saber o que cada coisa faz...

Falow.

[6] Comentário enviado por tenchi em 23/01/2007 - 16:57h

Ah, e valew à todos que elogiaram este artigo...
E leiam o primeiro comentário, pois ele esclaresce algumas falhas do artigo.

[7] Comentário enviado por linus black em 23/01/2007 - 17:38h

gostei mas eu estou com uma duvida cruel!!!
eu poderia por ex: criar anexando caminhos de icones as strings para automatizar a execução do script com entesão de criar um programa baseado nesta explanação. e como posso proceder.. 10 Já fiquei fãn deste cara...

[8] Comentário enviado por dailson em 24/01/2007 - 10:13h

Oi Tenchi

Na variável STRING não estou usando aspas e sim acento grave ` `
Mas o problema não estava ai e sim nas aspas do sed, quando retirei as aspas tudo funcionou normalmente!!!
Valeu a dica da depuração!!!!
E mais uma vez, parabéns!!

Dailson

[9] Comentário enviado por tenchi em 24/01/2007 - 21:43h

Então dailson, era dessas que eu tava falando! rss.
Foi mal, é que eu não sou muito bom nesse negócio de expressões regulares...
"Essas expressões regulares ainda vão me matar do coração"

Falow.

[10] Comentário enviado por tenchi em 29/05/2007 - 14:09h

Ah, e para quem gostou deste artigo, por favor leiam sua "continuação":
http://www.vivaolinux.com.br/artigos/verArtigo.php?codigo=6107

Mais uma vez, muito obrigado, e qualquer dúvida, basta me mandar um e-mail.

[11] Comentário enviado por vanervainer em 29/02/2008 - 17:40h

Execelente Artigo!!! Parabéns!!!

[12] Comentário enviado por stewe em 06/05/2013 - 19:53h

fantástico mano


parece fácil


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts