Cleiton Bueno
Sistemas Embarcados, Programação Multiplataforma, Linux Embarcado e vivência open-source
Shell Script – Estrutura de repetição e
arrays
Estruturas de repetição em shell script, como em demais linguagens aqui teremos o for, while e o until e irei aproveitar o engajado para passar arrays em Shell Script que �cara perfeito com estrutura de repetição.
FOR
Estrutura bem parecida com a de outras linguagens porém com varias maneiras de implementar, podemos na própria estrutura For de�nir o numero de elementos “1 2 3 4 5”, ou uma sequencia “seq 10” e ele irá repetir até o �m desta condição.
Exemplo: 1 2 3 4 for [ condição ]; do #Seu codigo done
WHILE
Muito parecido com o For, pode praticamente fazer a mesma coisa porém uma de�nição mais claro entre os dois é que o For irá iniciar em um valor e irá parar quando chegar em outro de�nido, o while também pode trabalhar assim além de continuar no laço enquanto a condição for verdadeira.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #!/bin/bash #Exemplo 1
echo "Contando ate 5" for i in 1 2 3 4 5; do
echo $i; done #Exemplo 2
echo "Contando ate 10" for i in $(seq 10); do
echo $i; done #Exemplo 3
echo "Contando ate 5 la estilo C" for ((i=0; i<=5; i++))
do
echo "Executando o $i" done 1 2 3 4 while [ condição ]; do #Seu codigo done
Exemplo:
UNTIL
Imagine o oposto do While, pois é esse é o until, no while enquanto é executado o laço enquanto a condição é verdadeira no until é executado enquanto for falsa.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #!/bin/bash #Exemplo 1 BLOG="www.cleitonbueno.wordpress.com"
while [ "$BLOG" = "www.cleitonbueno.wordpress.com" ]; do
echo "Esse blog eh show!!!" done #Exemplo2 var_control=0 while true; do if [ $var_control -gt 10 ]; then break fi
echo Valor $var_control
# Incrementando var_control, funciona apenas em Bash (( var_control++ ))
done
1
Exemplo:
Então em Shell Script temos esses três modos para repetição, os mais utilizados são for e while, os exemplos acima são apenas uma pequena amostra de como implementar porém começa a �car interessante com o uso de array.
Array
Vetores ou arrays em qualquer linguagem de programação você irá utilizar ou se não irá 3
4 #Seu codigodone
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #!/bin/bash response=yes count=0
until [ "$response" = "no" ]; do
(( count++ )) echo "Laco $count" #if [ $count -eq 5 ]; if [ $count -ge 5 ]; then response=no fi sleep 1 done
implementar um modo de manipular e no Shell Script não é diferente, array pode ser declarado da seguinte maneira:
num[0]=”10″ num[1]=”20″ num[2]=”30″ num[3]=”40″ num[4]=”50″ ou
nomes=(“Cleiton” “Manoel” “Pedro” “Paulo”) Vamos ao exemplo com o arquivo forEx1.sh:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #!/bin/bash num[0]="10" num[1]="20" num[2]="30" num[3]="40" num[4]="50"
nomes=("Cleiton" "Manoel" "Pedro" "Paulo")
# O que diferencia de uma variavel comun é o ${ } e dentro o array com a posição echo "Numero 2 : ${num[1]}"
echo "Numero 4 : ${num[3]}" echo "Nome 1 : ${nomes[0]}" echo "Nome 4 : ${nomes[3]}"
Saída:
Agora um exemplo mais do dia-a-dia, vamos implementar um Shell Script para bloquear algumas portas com iptables, exemplo forEx2.sh:
Vamos entender o exemplo acima, temos o nosso array PORT=(“137” “138” “139” “445” “22” “80” “443”), onde eu criei um for que irá pegar o tamanho do array ${PORT[@]} e um a um vai sendo lido e armazenado no $porta onde executo minha regra de bloqueio com iptables. Poderíamos melhoras esse script, separando as portas/serviços TCP dos UDP e colocando uma descrição, �caria legal.
Vamos então ao exemplo forEx3.sh: 1 2 3 4 5 6
cleiton@linuxVM:~/projetos/shell script$ ./forEx1.sh Numero 2 : 20
Numero 4 : 40 Nome 1 : Cleiton Nome 4 : Paulo
bueno@ti-cleiton ~/projetos/shell_script $
1 2 3 4 5 6 7 8 9 10 11 #!/bin/bash PORT=("137" "138" "139" "445" "22" "80" "443") echo -e "nExemplo de regras para firewall" for porta in ${PORT[@]}
do
echo "Bloqueando a porta $porta"
iptables -A INPUT -p udp --dport $porta -j DROP iptables -A INPUT -p tcp --dport $porta -j DROP done
Saída:
Esse �cou mais completo, foi a mesma ideia porem com mais dois arrays do protocol_portas e desc_portas, e temos uma variável $i do for que baseado no tamanho do array irá ser o
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #!/bin/bash portas=("137" "138" "139" "445" "22" "80" "443")
protocol_portas=("udp" "udp" "tcp" "tcp" "tcp" "tcp" "tcp")
desc_portas=("NetBIOS" "NetBIOS" "NetBIOS" "SMB" "SSH" "HTTP" "HTTPS")
echo -e "nExemplo de regras para firewall com descricao e identificacao de protocolo" echo -e "nSERVICOtPORTAtPROTOCOLOtSTATUS"
for ((i=0; i<${#portas[@]}; i++)) do
if [ "${protocol_portas[$i]}" = "tcp" ]; then
iptables -A INPUT -p tcp --dport ${portas[$i]} -j DROP echo -e "${desc_portas[$i]}t${portas[$i]}tTCPttBLOQUEADO" elif [ "${protocol_portas[$i]}" = "udp" ];
then
iptables -A INPUT -p udp --dport ${portas[$i]} -j DROP echo -e "${desc_portas[$i]}t${portas[$i]}tUDPttBLOQUEADO" fi done 1 2 3 4 5 6 7 8 9 10 11 12
cleiton@linuxVM:~/projetos/shell script$ ./forEx3.sh
Exemplo de regras para firewall com descricao e identificacao de protocolo SERVICO PORTA PROTOCOLO STATUS
NetBIOS 137 UDP BLOQUEADO NetBIOS 138 UDP BLOQUEADO NetBIOS 139 TCP BLOQUEADO SMB 445 TCP BLOQUEADO SSH 22 TCP BLOQUEADO HTTP 80 TCP BLOQUEADO HTTPS 443 TCP BLOQUEADO
identi�cado dos três arrays para exibir ou usar algum valor.
Agora um script útil utilizando o while, vamos ano nosso whileEx1.sh: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #!/bin/bash if [ -z $1 ] then
echo -e "Parametro PID deve ser informado!" exit
fi
# TIME_WAIT eh em segundos entao temos (60s * VALOR) para intervalo em minutos de espera #TIME_WAIT=60 # 1 minuto
#TIME_WAIT=300 # 5 minutos TIME_WAIT=3600 # 1 hora LOCK_FILE="/tmp/$RANDOM" PID=$1
echo -e "Arquivo de log criado com sucesso em $LOCK_FILE" echo -e "Iniciando monitoramento..."
echo -e "Inicio do log `date +%D_%T`" > $LOCK_FILE while [ -d /proc/$PID ];
do
if [ `date +%H%M` -ge 1200 ]; then
echo -e "O processo $$ deve ser morto, passou 12horas de execucao" >> $LOCK_FILE # Enviar e-mail para sysadmin com sendmail e como corpo o $LOCK_FILE
# COMANDO AQUI rm -Rf $LOCK_FILE exit
else
echo -e "Script executando. Data/Hora: `date +%D_%T`" >> $LOCK_FILE echo -e "Comando: `cat /proc/$PID/cmdline`" >> $LOCK_FILE
echo -e "n" >> $LOCK_FILE fi
Saída:
Analisando o nosso arquivo de log:
Vamos entender nosso script. Ele faz parte de um processo que tenho onde começa a ser executado dia sim dia não onde varias coisas são feitas, porém ocorreu de algumas vezes esse meu script travar, e como eu sei que quando bem sucedido ele leva em torno de 6 horas, eu criei um outro script que é chamado e passado o PID desse meu script principal, então meu
36 37 38 39 40 41 42 done
echo -e "Processo finalizado com sucesso." >> $LOCK_FILE echo -e "Data/hora: `date +%D_%T`" >> $LOCK_FILE
# Enviar e-mail para sysadmin com sendmail e como corpo o $LOCK_FILE # COMANDO AQUI
rm -Rf $LOCK_FILE
1 2 3
cleiton@linuxVM:~/projetos/shell script$ ./whileEx3.sh 20648 Arquivo de log criado com sucesso em /tmp/9503
Iniciando monitoramento... 1 2 3 4 5 6 7 8 9 10 11 12 13
cleiton@linuxVM:~/projetos/shell script$ tail -f /tmp/9503 Inicio do log 03/03/14_15:58:44
Script executando. Data/Hora: 03/03/14_15:58:44 Comando: /usr/sbin/fcgi-pm-kstart
Script executando. Data/Hora: 03/03/14_16:58:44 Comando: /usr/sbin/fcgi-pm-kstart
Script executando. Data/Hora: 03/03/14_17:58:44 Comando: /usr/sbin/fcgi-pm-kstart
Script executando. Data/Hora: 03/03/14_16:04:44 Comando: /usr/sbin/fcgi-pm-kstart
segundo script que é algo bem próximo ao exemplo acima irá monitorar o /proc/NUM_PID_FORNECIDO se este diretório existir quer dizer que o processo esta rodando e a sacada é o if [ date +%H%M -ge 1200 ], se o script for maior que 1200 seria 12:00 do dia ae sei que algo seu problema e o log é enviado para o meu e-mail para eu tomar as devidas providencias, no meu caso ele já é morto com um kill.
Foi uma pequena amostra do poder do Shell Script agora unindo if, while e variáveis, e para não virar bagunça apos enviar nosso arquivo de log por e-mail ele é removido no �nal do script se bem sucedido ou logo apos ultrapassar as 12horas de execução.
Nosso ultimo script dessa vez utilizando o for para uma tarefa de backup, vamos ver nosso forEx4.sh: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #!/bin/bash #Parte1 SRC="/home/bueno/projetos/shell_script/" DST="/mnt/backups/vm.03/bueno/" cd $SRC
LS_DIR=$(find * -maxdepth 0 -type d) for folder in $LS_DIR;
do
tar -czf $DST$folder.tgz $folder > /dev/null done
#Parte2
USER_ID=($(cat /etc/passwd | cut -d: -f3)) USER_DIR=($(cat /etc/passwd | cut -d: -f6)) DST_HOME="/tmp/"
Agora foi uma promoção heim, ta lendo um e vai aprender dois *rs, como pode-se ver eu �z dois scripts no nosso exemplo acima, vamos entender o primeiro Parte1, as variáveis DST e SRC dizem por si só que um serio o destino e outra a origem, eu acesso a origem na linha 7 e logo em seguida executo o comando �nd no diretório corrente e a saída �cara na variável LS_DIR, o meu �nd ira pesquisar tudo que for diretório -type d e estiver ali apenas -maxdepth 0 se eu coloca-se 1 seria 1 grau de dependência então avançaria até 1 diretório adiante.
Baseado no que estiver no LS_DIR sera os caminhos dos diretórios que eu irei compactar com o tar na linha12 e la esta o destino com o nome do .tgz e na frente cada diretório encontrado, então olha como se comporta essa primeira parte abaixo:
Na Parte2 tem uma sacadinha que �z questão de mostrar e por isso dois exemplos, ele irá 20
21 22 23
for ((i=0; i<${#USER_ID[@]}; i++)) do if [ ${USER_ID[$i]} -ge 1001 -a ${USER_ID[$i]} -lt 65500 ]; tar -czf $DST_HOME$USER_NAME.tgz ${USER_DIR[$i]} > /dev/null
fi done 1 2 3 4 5 6 7 8 9 10 11 12 13
cleiton@linuxVM:~/projetos/shell script$ ls -1 estrutura_case/
estrutura_condicional/
estrutura_repeticao/
scripts/
variaveis/
cleiton@linuxVM:/mnt/backups/vm.03/bueno$ ls -1 estrutura_case.tgz
estrutura_condicional.tgz estrutura_repeticao.tgz scripts.tgz
fazer algo importante, backup de “todos” os usuários do computador, muitos scripts na internet realizam backup de tudo que esta no /home, porém tem alguns usuários que o diretório padrão não é o home como Nagios e Zabbix e ae não se torna tão e�ciente, e para este caso elaboramos o Parte2 do forEx4.sh.
As variáveis USER_ID e USER_DIR uma ira obter o UID de todos os usuários e a outra o diretório padrão, tenho DST_HOME que serão o destino do meu backup utilizei o /tmp para exemplo, e ae entro em uma estrutura de repetição de 0 até o numero total de elementos UID encontrados, onde por cada UID veri�co se é maior que 1000 e menor que 65500, já que acima de 1000 são usuários comuns e abaixo de 1000 usuários do sistema, atendendo essa logica irei pegar o nome do usuário no /etc/passwd poderia usar regex no USER_DIR(preguiça rs), com isso em mãos é o mesmo tar utilizado agora apenas com uma variável de controle $i para identi�car o usuário, vamos ver como se comportou a execução desta segunda etapa:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
cleiton@linuxVM:~/projetos/shell script$ cat /etc/passwd root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
www-data:x:33:33:www-data:/var/www:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh rtkit:x:110:119:RealtimeKit,,,:/proc:/bin/false
hplip:x:111:7:HPLIP system user,,,:/var/run/hplip:/bin/false cleiton:x:1000:1000:Cleiton Bueno,,,:/home/cleiton:/bin/bash bueno:x:1001:1001:Bueno,,,:/home/bueno:/bin/bash
projeto:x:1002:1002:Projetos,,,:/home/projeto:/bin/false sshd:x:113:65534::/var/run/sshd:/usr/sbin/nologin
A maior sacada neste exemplo foi: Parte1
LS_DIR=$(�nd * -maxdepth 0 -type d) Parte2
USER_ID=($(cat /etc/passwd | cut -d: -f3))
Os dois executam comandos e armazenam em uma variável, a Parte1 é exatamente desta maneira já a Parte2 quando usamos VARIAVEL=($(COMANDO)), estou falando que meu resultado ira entrar em um array.
Espero ter passado a ideia de repetição e o uso da mesma em shell script foram vários exemplos e com praticas sem mais delongas que podem ser usadas no dia-a-dia, qualquer duvida insira um comentário.
Até a próxima! 16 17 18 19 20 21 22 23 24
postgres:x:115:124:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash openfire:x:123:129:Openfire XMPP server,,,:/var/lib/openfire:/bin/false nagios:x:1003:1003:Nagios,,,:/opt/nagios:/bin/sh
cleiton@linuxVM:~/projetos/shell script$ ls -l /tmp/
bueno.tgz cleiton.tgz nagios.tgz projeto.tgz
Shell Script – Estrutura de repetição e arrays by Cleiton Bueno is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
License.
Tagged as: ($()), $(), backup shell script, estrutura de repetição, for, laço shell script, loop shell script, shell script, shell script for, until, while
Categorized in: Shell Script
Compilando Android para Raspberry PI 2 B
14 comments •6 months ago•
Cleiton Bueno — Olá Tiago, eu nunca fiz mas sei o caminho para fazer, segue alguns …
Arduino – Comunicação UDP Parte1
6 comments •2 years ago•
Cleiton Bueno — Olá Paulo, sobre RFID aqui com Arduino não tenho nenhum artigo, escrevi um sobre RFID mas é utilizando Linux com a Linux – PinMux Utility V3 agora para Linux
3 comments •2 years ago•
Cleiton Bueno — Realmente ficaria perfeito Josenivaldo, mas pelo que vi nesta versão ainda não é possível, ele apenas gera, eu ainda
Migração para cleitonbueno.com
2 comments •2 years ago•
Cleiton Bueno — Esta semana estou
finalizando os últimos detalhes da migração manotroll, se você já possui o e-mail
ALSO ON WWW.CLEITONBUENO.COM
0 Comments www.cleitonbueno.com
1 LoginShare
⤤
Sort by BestStart the discussion…
Be the first to comment.
Subscribe
✉ dAdd Disqus to your site Add Disqus Add 🔒 Privacy
Recommend