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 e case)

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’

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Post comment