Shell Script: vetores

Um array mantêm uma série de elementos de dados, geralmente do mesmo tamanho e tipo de dados. Elementos individuais são acessados por sua posição no array, cuja posição é dada por um índice (geralmente, dentro de uma sequência de números inteiros). É conhecido como vetor, caso seja uni-dimensional, ou matriz, para um array bi-dimensional. Vejamos alguns pontos importantes e exemplos de uso de vetores em shell script (utilizado interpretador de comandos compatível com o sh, que é o bash).

Em um vetor, os elementos são separados por um espaço. Neste caso, o espaço não é um caractere (' '), e sim um separador dos elementos. Vejamos esse exemplo de vetor e o acesso às diferentes posições e elementos do vetor:

aeroportos=("cgh" "gru" "bsb" "sdu")

Nesse caso, aeroportos[0] é "cgh", aeroportos[1] é "gru" e assim por diante. Para imprimir na tela o conteúdo de uma posição do vetor, temos:

$ echo ${aeroportos[1]}

Para exibir todos os elementos de um vetor, devemos usar a mesma estrutura, mas no lugar do índice, utilizar arroba [@] ou asterisco [*]. Veja o exemplo a seguir de uma rotina para copiar os dados de computadores em diferentes aeroportos para um computador de backup, onde cada diretório possui como nome a data do dia na forma ANO-MES-DIA:

#!/bin/bash
#crontab -e: [minutos] [horas] [dias do mês] [mês] [dias da semana] [usuário] [comando]
#59 23 * * * receiver ./transmite.sh
data=`date +%F`
ano=`date +%Y`
#IPs dos aeroportos estao definidos em /home/locator/.ssh/config na máquina com o script
aeroportos=("cgh" "gru" "bsb" "sdu")
aeroporto=("Congonhas" "Guarulhos" "Brasilia" "Santos_Dumont")
LIMITE=`echo ${aeroportos[*]} | wc -w`
for ((i=0; i <= $LIMITE-1 ; i++))  do # Mandar pra BACKUP no PC "ip"
 sshpass -p "SENHA" rsync -azvr --progress user@${aeroportos[$i]}:/home/dados/$data user@ip:/dados/${aeroporto[$i]}/BACKUP/$ano 
done 

Para exibir o intervalo fechado de i até i+k, use:

 $ echo ${vetor[@]:$i:((k+1))} 

Outro exemplo, que conta o número de arquivos de diretórios (listados em cada linha do arquivo lista_dias.txt) e imprime o total em linhas do arquivo controle_aeroporto.txt

 #!/bin/bash
# Listar diretórios/arquivos que faltam comparando com total de arquivos
aeroportos=("cgh" "gru" "bsb" "sdu")
for x in "${aeroportos[@]}"; do
 	cd /dados/$x/BACKUP
 	for i in $(cat ../../lista_dias.txt); do
 		total_arq=0
 		linha_dir=""
 		total_arq=""
 		data=(`echo $i | tr "-" "\n"`)
 		ano=${data[0]}
 		linha_dir=`ls $ano | grep $i`
 		# Se o diretorio existir...
 		if [ -n $linha_dir ]; then
 			total_arq=`ls $ano/$i | wc -l`
 			echo $total_arq
 		else
 			echo "0"
 		fi
 	done > /dados/controle_$x.txt 2> /dev/null
done

Para copiar o vetor original para uma nova variável, não basta fazer da mesma forma que é feito com uma variável. Além de indicar que deseja copiar todos os seus elementos, deve colocar novamente parênteses para transformar o conteúdo em elementos de um novo vetor:

copy=(${original[*]})

Se não fizer isso, todos os elementos do vetor original viram uma única posição em uma variável. Uma discussão com exemplos é realizada no blog do Ahmed Amayem.

Para um script receber um vetor como argumento, ele deve ser inserido na chamada dessa rotina da seguinte forma:

$ teste.sh $arg1 "Sub" $arg3 $arg4 "${vetorum[@]}" "${vetordois[@]}"

Note que foram passados quatro variáveis e dois vetores. Para o shell script receber esses valores, não será possível receber um vetor como uma variável só. Assim, a ideia é tratar TODOS os elementos (incluindo os elementos dos vetores) como sendo um único array e depois separar as variáveis fora dos vetores. Veja o exemplo:

#!/bin/bash
## Script para receber array como argumento

# Recebe todos os argumentos como um único array
array=( "$@" )
tamanho=${#array[@]}
inicio=4 # Número de elementos fora dos vetores

# Guardar os primeiros elementos como variáveis
hist_fim=${array[0]}
tipo=${array[1]}
flag_mes=${array[2]}
flag_ophen=${array[3]}

# Percorrer vetor para trabalhar variáveis
for ((i=$inicio; i <= $tamanho-1 ; i++)); do
	elemento=${array[$i]}
	echo $elemento
done

Por último, um exemplo com uns vetores enormes de mês, dia e hora (a cada 15 minutos). Seu objetivo é descompactar arquivos ".tar.gz" (ou ".tar.bz2") e unir os conteúdos em outro arquivo final (também apaga diretório que não será mais usado e compacta arquivo):

#!/bin/bash
ano=2009
mes=("01" "02" "03" "04" "05" "06" "07" "08" "09" "10" "11" "12")
dia=("01" "02" "03" "04" "05" "06" "07" "08" "09" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "20" "21" "22" "23" "24" "25" "26" "27" "28" "29" "30" "31")
hora=("0000" "0015" "0030" "0045" "0100" "0115" "0130" "0145" "0200" "0215" "0230" "0245" "0300" "0315" "0330" "0345" "0400" "0415" "0430" "0445" "0500" "0515" "0530" "0545" "0600" "0615" "0630" "0645" "0700" "0715" "0730" "0745" "0800" "0815" "0830" "0845" "0900" "0915" "0930" "0945" "1000" "1015" "1030" "1045" "1100" "1115" "1130" "1145" "1200" "1215" "1230" "1245" "1300" "1315" "1330" "1345" "1400" "1415" "1430" "1445" "1500" "1515" "1530" "1545" "1600" "1615" "1630" "1645" "1700" "1715" "1730" "1745" "1800" "1815" "1830" "1845" "1900" "1915" "1930" "1945" "2000" "2015" "2030" "2045" "2100" "2115" "2130" "2145" "2200" "2215" "2230" "2245" "2300" "2315" "2330" "2345")
# para cada arquivo tar
for ((m=3; m <= 11 ; m++))
do
	arquivotar="$ano-"${mes[$m]}"_arquivos.tar.gz"
	#arquivotar="$ano-"${mes[$m]}"_arquivos.tar.bz2"
	# se o arquivo existir, descompactar
	if test -f $arquivotar
	then
		ndir="$ano-"${mes[$m]}""
		mkdir $ndir
		tar -zxvf $arquivotar #descompacta gz
		#tar -jxvf $arquivotar # descompacta bz2
		# para cada pasta aberta (ou seja, para cada dia)...
		for ((i=0; i <= 30 ; i++))
		do
			diretorio="$ano-"${mes[$m]}"-"${dia[$i]}""
			arq="$ano-"${mes[$m]}"-"${dia[$i]}".dat"
			# se o diretorio existir
			if test -d $diretorio
			then
				# para cada arquivo de 15 min
				for ((h=0; h <= 95 ; h++)); do arquivo="$ano-"${mes[$m]}"-"${dia[$i]}"_"${hora[$h]}".dat" # se arquivo existir, concatenar o arquivo dentro do arquivo final test -f $diretorio/$arquivo && cat $diretorio/$arquivo >> $ndir/$arq
				done
				# apagar pasta do dia
				rm -rf $diretorio
				# compactar arquivo
				gzip $ndir/$arq
			fi
		done
		# mover a pasta para dados
		mv $ndir ../../dados
	fi

done

Fontes: Viva o Linux - Brincando com vetores e Stack Overflow.

Compartilhe o link desse texto, mas se for copiar algum trecho, cite a fonte. Valorize nosso trabalho.
Mais informações na licença de uso do site.

2 Pingbacks/Trackbacks