Scripts Prontos: Loops bash
Imagine o seguinte cenário: você quer saber o número de arquivos em 20 diretórios diferentes, todos nomeados de maneira aleatória: SP-1, RJ-3, RS-12....
A alternativa mais óbvia é entrar nos diretórios individualmente e lançar:
ls -l | wc -l
Mas fazer isso 20 vezes seria trabalhoso e propenso a erros, felizmente, o shell script oferece uma solução que muitos não conhecem: loops, ou seja, a opção de realizar uma série de comandos repetida e automaticamente.
O loop 'for'
Para resolver o cenário acima usando o "for" você precisa apenas listar os nomes juntamente ao comando. No exemplo abaixo, eu listo os diretórios na chamada do loop e me refiro a eles como "dir", depois, armazeno os resultados individualmente em uma variável "total", a qual eu imprimo na linha seguinte, permitindo uma visualização mais amigável:
for dir in AM-12 ES-87 MG MG-2 MT-01 RJ RJ-12 RJ-3 RS-12 RS-3 RS-12 ES-77 TO MG-20 MT-11 RJ-6 AC-12 PA-3 PA-12 GO-3; do
total=`ls -l $dir | wc -l`;
echo "$dir - $total"
done;
Executando o script acima, teremos:
AM-12 - 12
ES-87 - 0
MG - 140
MG-2 - 14
MT-01 - 90
RJ - 98
RJ-12 - 25
RJ-3 - 10
RS-12 - 0
RS-3 - 67
RS-12 - 23
ES-77 - 11
TO - 24
MG-20 - 91
MT-11 - 12
RJ-6 - 42
AC-12 - 23
PA-3 - 0
PA-12 - 12
GO-3 - 12
Se você quiser salvar o resultado em um csv para análise, basta trocar o " - " por "," e direcionar o output para o arquivo com ">> .csv"
for dir in AM-12 ES-87 MG MG-2 MT-01 RJ RJ-12 RJ-3 RS-12 RS-3 RS-12 ES-77 TO MG-20 MT-11 RJ-6 AC-12 PA-3 PA-12 GO-3; do
total=`ls -l $dir | wc -l`;
echo "$dir , $total"
done >> arquivo.csv;
Mas e se eu quiser ler apenas os arquivos com determinadas datas, por exemplo: 20221203, 20221204, 202205, etc...? Para isso, podemos usar um loop dentro do outro:
for data in 20221203 20221204 20221205 20221206 20221207; do
for dir in AM-12 ES-87 MG MG-2 MT-01 RJ RJ-12 RJ-3 RS-12 RS-3 RS-12 ES-77 TO MG-20 MT-11 RJ-6 AC-12 PA-3 PA-12 GO-3; do
total=`ls -l $dir | grep $data | wc -l`;
echo "$data - $dir - $total"
done;
done;
Teremos como resultado:
20221201 - AM-12 - 1
20221201 - ES-87 - 0
20221201 - MG - 140
20221201 - MG-2 - 14
...
20221202 - AM-12 - 1
20221202 - ES-87 - 0
20221202 - MG - 140
20221202 - MG-2 - 14
...
20221203 - AM-12 - 1
20221203 - ES-87 - 0
20221203 - MG - 140
20221203 - MG-2 - 1
...
Você pode usar quantos loops quiser, só tome cuidado com seu uso de RAM e CPU.
Mas e se o número de diretórios que eu quiser monitorar for grande, na casa dos milhares talvez? Bem, se os diretórios/arquivos seguirem alguma lógica do tipo: arquivo.log, arquivo.log.1, arquivo.log.2, arquivo.log.3... podemos utilizar uma opção para gerar sequências:
Recomendados pelo LinkedIn
for i in {1..20}; do
x=`cat arquivo.log.$i | wc -l`;
echo "arquivo.log.$i , $x";
done;
Se por algum motivo você quiser utilizar um passo específico (de dois em dois, três em três), basta fazer:
for i in {10..200..10}; do
x=`cat arquivo.log.$i | wc -l`;
echo "arquivo.log.$i , $x";
done;
Esse loop irá iterar por todos os arquivos terminados com um múltiplo de 10 entre 10 e 200. Você pode conferir alguns outros exemplos no artigo abaixo:
Mas e se os arquivos/diretórios não seguiram uma lógica simples? E se eles estiverem distribuídos entre vários diretórios diferentes com nomes aleatórios? Felizmente, o bash já vem com uma opção pronta.
O loop 'while'
Suponha que você queira executar uma mesma ação sobre milhares de arquivos, por exemplo, contar o número de linhas em cada um. Escrever todos os nomes em um único loop não seria viável, obviamente, mas podemos armazená-los em um arquivo "txt" como o exemplo abaixo....
/var/log/monitoracao-1/arquivo_de_log-1.log
/var/log/monitoracao-2/arquivo_de_log.log
/var/log/monitoracao-3/arquivo_de_log.log
/var/log/monitoracao-4/arquivo_de_log.log
/home/joao/desktop/monitoracao-5/arquivo.csv
/home/pedro/desktop/monitoracao-6/arquivo.csv
...
...e ler esse arquivo com o loop while, para isso, usamos o comando read associado ao "<":
while read line:
x=`cat $line | wc -l`;
echo "$line - $x";
done < arquivo.txt;
Basta agora exportar para um csv e você pode monitorar o crescimento dos seus logs tranquilamente.
Por fim, sobra a situação em que você quer que o loop continue executando até que uma condição específica seja atendida. Para isso, basta usarmos uma variável para monitorar a situação monitorada e fazer como no loop abaixo:
num=`ls -l diretorio_qualquer | wc -l`;
while [[ $num -le 200 ]]; do
sleep 10;
num=`ls -l diretorio_qualquer | wc -l`;
done;
echo "ALERTA!!!!"
O loop acima vai contar o número de arquivos em um diretório em intervalos de 10 segundos e caso o número ultrapasse 200, o loop se encerra e um alerta é emitido para o usuário.
Conclusão
Os scripts apresentados aqui são apenas a ponta do iceberg no potencial de loops no Linux. Se deseja fazer algo realmente incrível, pesquise mais sobre o Linux, ou siga Iago Ferreira para mais dicas. O shell script é um mundo de possibilidades para facilitar nossas vidas, cabe a você explorar!
Agradeço a atenção, espero que seja útil.
Devops Engineer | Cloud | SRE | Ajudo profissionais e empresas a migrarem para área de CLOUD/DEVOPS.
2 aMuito top! Parabéns pelo conteúdo 👏