Aula 11 – O loop ‘for’
Aula 10 – Expansões de Parâmetros | Índice | Aula 12 – Loops ‘while’ e ‘until’
Seu apoio é muito importante para a criação e a manutenção dos cursos gratuitos do canal debxp:
11.1 – Comandos compostos
O loop for
faz parte de uma categoria de comandos chamada de comandos compostos,
que são estruturas de linguagem que agrupam comandos ou são compostas por um blocos de controle e execução de comandos:
- Agrupamento de comandos com parêntesis
- Agrupamento de comandos com chaves
- Estruturas de repetição (
for
,while
,until
) - O menu
select
- Estruturas de decisão (
if
ecase
)
Estando no grupo das estruturas de repetição, a função do for
é percorrer sequencialmente cada elemento de uma lista executando comandos. Durante cada iteração (cada ciclo), o loop for
armazena o valor da lista que está sendo lido no momento em uma variável.
11.2 – Sintaxe
A sintaxe geral do loop for
é:
for NOME [in LISTA]; do
COMANDOS
done
Onde LISTA
pode ser uma expansão de uma string com elementos separados por espaços, arrays, expansões de nomes de arquivos ou expansões de chaves. Caso a expressão in LISTA
seja omitida, o Bash presumirá a sintaxe abaixo:
for NOME in "$@"; do
COMANDOS
done
Onde $@
são todos os parâmetros posicionais passados na linha de comando ($1
, $2
, $3
…).
Alternativamente, o loop for
pode trabalhar avaliando expressões, como na linguagem C:
for (( expressão1; expressão2; expressão3 )); do
COMANDOS
done
Onde…
- expressão1 é uma atribuição de um valor inicial;
- expressão2 é uma expressão condicional que espera uma avaliação falsa para indicar o fim do loop;
- expressão3 é uma atualização do valor inicial.
Por exemplo:
for (( n = 1; n <= 5; n++ )); do
echo $n
done
Neste caso, o valor inicial de n
é 1
e, a cada ciclo, ele será incrementado em +1
até a avaliação expressão condicional resultar em falso. Deste modo, o comando echo
será executado enquanto o valor de n
for menor ou igual a 5
, resultando em:
1
2
3
4
5
11.3 – Percorrendo as palavras em uma string
Qualquer string com elementos separados por espaços pode ser passada para o loop for
como uma LISTA
.
Por exemplo:
:~$ alunos='João Maria Luis Carlos'
:~$ for nome in $alunos; do echo $nome; done
João
Maria
Luis
Carlos
Isso teria o mesmo efeito de…
:~$ for nome in João Maria Luis Carlos; do echo $nome; done
João
Maria
Luis
Carlos
Para utilizar outros separadores que não sejam espaços, é necessário alterar temporariamente o valor na variável IFS
(o separador interno de campos). Por exemplo, se quisermos passar uma string separada por vírgulas como LISTA
:
alunos='João,Maria,Luis Carlos'
# Salvando o IFS para restauração...
IFS_ORIGINAL=$IFS
# Alterando o IFS...
IFS=','
# Executando o loop...
for nome in $alunos; do echo $nome; done
# Restaurando o IFS original...
IFS=$IFS_ORIGINAL
A saída seria:
João
Maria
Luis Carlos
Nos scripts, a menos que existam outros blocos de código dependendo dos valores originais, não é necessário salvar e restaurar o valor de IFS, já que qualquer alteração dos separadores originais ficará restrita apenas à sessão de execução do script.
Quando a string possui quebras de linha (caractere de controle \n
) como separadores de campos, o IFS pode ser alterado utilizando uma expansão de aspas de que nós ainda não falamos, e que expande o significado de caracteres ANSI-C em uma string…
$'...' --> Expande caracteres no padrão ANSI-C
Esses caracteres são sequências iniciadas com a barra invertida e representam, em boa parte, os chamados caracteres de controle, como a quebra de linha (\n
), a tabulação horizontal (\t
), e outros caracteres escapados.
Veja o exemplo:
:~$ alunos=$'João\nMaria\nLuis Carlos'
Neste caso, as quebras de linha seriam expandidas pelo shell, o que pode ser verificado fazendo…
:~$ echo "$alunos"
João
Maria
Luis Carlos
# Sem aspas, não seria possível perceber a diferença...
:~$ echo $alunos
João Maria Luis Carlos
# Obviamente, com aspas simples não haveria a expansão do '$'...
:~$ echo '$alunos'
$alunos
Ainda neste mesmo caso, a variável IFS
deveria ser alterada para \n
antes de podermos utilizar alunos
como a LISTA
de um loop for
…
:~$ IFS=$'\n' # Alterando o IFS...
:~$ for nome in "$alunos"; do echo "$nome"; done
João
Maria
Luis Carlos
11.4 – Percorrendo elementos de uma array
Se LISTA
for uma array, o loop for
percorrerá cada um de seus elementos armazenando seus valores ou seus índices na variável temporária.
Por exemplo:
:~$ frutas=("banana" "laranja" "mamão papaya")
# Armazenando os valores em ‘fruta’...
:~$ for fruta in "${frutas[@]}"; do echo $fruta; done
banana
laranja
mamão papaya
# Armazenando os índices em ‘fruta’...
:~$ for fruta in "${!frutas[@]}"; do echo $fruta; done
0
1
2
Também podemos percorrer os elementos de uma array associativa…
:~$ declare -A carros
:~$ carros[vw]="Fusca"
:~$ carros[fiat]="Palio"
:~$ carros[ford]="Corcel"
# Armazenando os valores em ‘carro’...
:~$ for carro in "${carros[@]}"; do echo $carro; done
Fusca
Palio
Corcel
# Armazenando os índices em ‘carro’...
:~$ for carro in "${!carros[@]}"; do echo $carro; done
vw
fiat
ford
11.5 – Percorrendo nomes de arquivos
As expansões de nomes de arquivos também podem ser usadas como uma LISTA
para o loop for
:
:~$ for arquivo in *.txt; echo $arquivo; done
teste1.txt
teste2.txt
teste3.txt
11.6 – Percorrendo faixas numéricas e alfabéticas
As listas podem ser geradas a partir de expansões de chaves que resultem em faixas numéricas ou alfabéticas, como nos exemplos abaixo:
:~$ for n in {1..5}; do echo $n; done
1
2
3
4
5
:~$ for s in {a..e}; do echo $s; done
a
b
c
d
e
# Incrementando em 2 passos...
:~$ for n in {1..5..2}; do echo $n; done
1
3
5
# Incrementando em 3 passos...
:~$ for s in {a..j..3}; do echo $s; done
a
d
g
j
Como podemos ver, graças à expansão de chaves, não precisamos trabalhar com expressões aritméticas quando o que queremos é, por exemplo, fazer com que o loop
for
dure um determinado número de ciclos.
11.7 – Controlando a execução do loop ‘for’
Se quisermos, a partir do resultado de um teste lógico, por exemplo, interromper a execução de um loop, basta utilizar o comando interno break
:
for n in {1..10}; do
[[ $n -gt 5 ]] && break || echo $n
done
Neste exemplo, o comando break
é invocado caso o valor de n
seja maior do que 5
.
A saída seria:
1
2
3
4
5
Na situação inversa, quando queremos que o loop continue, mas sem executar os demais comandos do bloco, nós podemos utilizar o comando interno continue
:
for n in {1..10}; do
[[ $n -lt 6 ]] && continue
echo $n
done
Aqui, o comando continue
será invocado em todos os ciclos onde n
é menor do que 6
, o que faz com que o loop continue sem a execução do comando echo
enquanto n
não for maior ou igual a 6
, resultando em…
6
7
8
9
10
Aula 10 – Expansões de Parâmetros | Índice | Aula 12 – Loops ‘while’ e ‘until’