Tudo o que você precisa saber sobre o Bash For Loops no Linux
Os scripts Bash são um meio altamente eficiente de automatizar tarefas, principalmente aquelas que tiram proveito de outros programas existentes. Essa automação geralmente requer a repetição de uma operação semelhante várias vezes, que é precisamente onde o loop for entra em ação.
Os administradores de sistema Linux e Mac geralmente estão familiarizados com scripts por meio do terminal, mas até mesmo os usuários do Windows podem entrar em ação com o subsistema Windows para Linux .
Como funcionam os scripts Bash
Um script bash é simplesmente um arquivo de texto simples contendo uma série de comandos que o shell bash pode ler e executar. Bash é o shell padrão no macOS pré-Catalina e na maioria das distribuições Linux.
Se você nunca trabalhou com um script de shell antes, deve começar com o caso mais simples absoluto. Isso permitirá que você pratique os conceitos-chave, incluindo a criação do script e sua execução.
Primeiro, crie o seguinte arquivo em um local conveniente (de preferência, abra um terminal e navegue até o diretório desejado primeiro):
#!/bin/bash
echo "Hello, World"
A primeira linha diz a qualquer coisa que execute este programa como executá-lo (ou seja, usando o interpretador bash). O segundo é apenas um comando como qualquer outro que você pode inserir na linha de comando. Salve esse arquivo como hello_world.sh e:
$ chmod +x hello_world.sh
$ ./hello_world.sh
O comando chmod na primeira linha torna o arquivo executável, o que significa que ele pode ser executado digitando seu nome, como na segunda linha.
Se você vir as palavras “Hello, World” impressas em uma linha em seu terminal, então tudo está funcionando conforme necessário.
Como funcionam os loops
Na programação geral, existem dois tipos principais de loop for: numérico e foreach . O tipo numérico é tradicionalmente o mais comum, mas no uso do bash, geralmente ocorre o contrário.
Os loops for numéricos normalmente se concentram em um único inteiro que determina quantas iterações serão realizadas, por exemplo:
for (i = 0; i < 100; i++) {
/* statements to execute repeatedly */
}
Este é um loop for de aparência familiar que irá iterar exatamente 100 vezes, a menos que i seja alterado dentro do loop ou outra instrução faça com que a execução do loop for pare.
Os loops Foreach, em contraste, tendem a operar em estruturas como listas ou matrizes e iterar para cada item dentro dessa coleção:
people = [ "Peter", "Paul", "Mary" ]
foreach (people as person) {
if (person == "Paul") {
...
}
}
Alguns idiomas usam uma sintaxe ligeiramente diferente que troca a ordem de coleção e item:
people = [ "Peter", "Paul", "Mary" ]
for (person in people) {
if (person == "Paul") {
...
}
}
For in Loops
No bash, o foreach – ou for in – loop é mais comum. A sintaxe básica é, simplesmente:
for arg in [list]
do
/* statements to execute repeatedly */
/* the value of arg can be obtained using $arg */
done
Por exemplo, para iterar por meio de três arquivos nomeados explicitamente:
for file in one.c two.c three.c
do
ls "$file"
done
Se esses arquivos existirem no diretório atual, a saída deste script será:
one.c
two.c
three.c
Em vez de um conjunto fixo de arquivos, a lista pode ser obtida por meio de um padrão glob (um incluindo curingas – caracteres especiais que representam outros caracteres). No exemplo a seguir, o loop for itera em todos os arquivos (no diretório atual) cujos nomes terminam em ".xml":
for file in *.xml
do
ls -l "$file"
done
Aqui está um exemplo de saída:
$ -rw-r--r-- 1 bobby staff 2436 3 Nov 2019 feed.xml
$ -rw-r--r-- 1 bobby staff 6447 27 Oct 16:24 sitemap.xml
Isso pode se parecer muito com uma maneira prolixa de fazer:
$ ls -l *.xml
Mas há uma diferença significativa: o loop for executa o programa ls 2 vezes diferentes, com um único nome de arquivo transmitido a ele a cada vez. No exemplo ls separado, o padrão glob (* .xml) corresponde aos nomes de arquivo primeiro e, em seguida, envia todos eles, como parâmetros de linha de comando individuais, para uma instância de ls .
Aqui está um exemplo que usa o programa wc (contagem de palavras) para tornar a diferença mais óbvia:
$ wc -l *.xml
44 feed.xml
231 sitemap.xml
275 total
O programa wc conta o número de linhas em cada arquivo separadamente e, em seguida, imprime uma contagem total em todos eles. Em contraste, se wc operar dentro de um loop for:
for file in *.xml
do
wc -l $file
done
Você ainda verá a contagem de cada arquivo:
44 feed.xml
231 sitemap.xml
Mas não há um resumo geral total porque wc é executado isoladamente, sempre que o loop é iterado.
Quando uma lista não é uma lista
Há um erro muito fácil e comum ao lidar com loops for, devido à maneira como o bash lida com argumentos / strings entre aspas. O loop em uma lista de arquivos deve ser feito assim:
for file in one.c two.c
Assim não:
for file in "one.c two.c"
O segundo exemplo inclui nomes de arquivos entre aspas duplas, o que resulta em uma lista com apenas um único parâmetro; o loop for será executado apenas uma vez. Este problema pode ser evitado usando uma variável em tais casos:
FILES="one.c two.c"
for file in $FILES
do
...
done
Observe que a própria declaração da variável precisa colocar seu valor entre aspas duplas!
Para sem uma lista
Sem nada para iterar, um loop for opera em quaisquer argumentos de linha de comando fornecidos ao script quando invocado. Por exemplo, se você tiver um script denominado args.sh contendo o seguinte:
#!/bin/sh
for a
do
echo $a
done
Em seguida, executar args.sh fornecerá o seguinte:
$ ./args.sh one two three
one
two
three
O Bash reconhece esse caso e trata para do como o equivalente de for a em $ @ do, onde $ @ é uma variável especial que representa os argumentos da linha de comando.
Emulando um Loop For Numérico Tradicional
Os scripts Bash geralmente lidam com listas de arquivos ou linhas de saída de outros comandos, portanto, o tipo de loop for in é comum. No entanto, a operação tradicional de estilo c ainda é compatível:
for (( i=1; i<=5; i++ ))
do
echo $i
done
Esta é a forma clássica com três partes nas quais:
- uma variável é inicializada (i = 1) quando o loop é encontrado pela primeira vez
- o loop continua enquanto a condição (i <= 5) for verdadeira
- a cada volta do loop, a variável é incrementada (i ++)
A iteração entre dois valores é um requisito comum o suficiente para que haja uma alternativa mais curta e um pouco menos confusa:
for i in {1..5}
do
echo $i
done
A expansão da chave que ocorre efetivamente traduz o loop for acima em:
for i in 1 2 3 4
Controle de loop mais fino com pausa e continuação
Os loops for mais complexos geralmente precisam de uma maneira de sair mais cedo ou de reiniciar imediatamente o loop principal com o próximo valor por vez. Para fazer isso, o bash usa as instruções break e continue que são comuns em outras linguagens de programação. Aqui está um exemplo que usa ambos para encontrar o primeiro arquivo com mais de 100 caracteres:
#!/bin/bash
for file in *
do
if [ ! -f "$file" ]
then
echo "$file is not a file"
continue
fi
num_chars=$(wc -c < "$file")
echo $file is "$num_chars characters long"
if [ $num_chars -gt 100 ]
then
echo "Found $file"
break
fi
done
O loop for aqui opera em todos os arquivos no diretório atual. Se o arquivo não for um arquivo regular (por exemplo, se for um diretório), a instrução continue é usada para reiniciar o loop com o próximo arquivo por vez. Se for um arquivo normal, o segundo bloco condicional determinará se contém mais de 100 caracteres. Nesse caso, a instrução break é usada para sair imediatamente do loop for (e chegar ao final do script).
Conclusão
Um script bash é um arquivo que contém um conjunto de instruções que podem ser executadas. Um loop for permite que parte de um script seja repetido muitas vezes. Com o uso de variáveis, comandos externos e as instruções break e continue, os scripts bash podem aplicar uma lógica mais complexa e realizar uma ampla gama de tarefas.