Loop Through the Lines of a File: Bash For Loop Explained

I want to loop through the lines of a file with a Bash script and one of the way to do it is using a for loop.

O que é um for loop?

A for loop é uma das construções de programação mais comuns e é usado para executar um determinado bloco de código dado um conjunto de itens de uma lista. Por exemplo, digamos que você queira escrever um programa que imprima o número de pessoas que vivem nas 10 maiores cidades européias. O programa pode usar um loop para percorrer cada cidade da lista e imprimir o número de pessoas para essa cidade.

A lógica executada é sempre a mesma e a única coisa que muda é a cidade.

Below você pode ver a sintaxe genérica de um Bash para loop:

for item in do command1 command2 ... commandNdone

LIST pode ser, por exemplo:

  • uma gama de números.
  • uma sequência de strings separadas por espaços.
  • a saída de um comando Linux (por exemplo, o comando ls).

Os comandos N entre fazer e fazer são executados para cada item da lista.

Para Loop no Bash

Neste artigo você aprenderá como usar o for loop no Bash e especificamente passar pelas linhas de um arquivo.

Mas por que você faria isso? Passando pelas linhas de um arquivo?

Por exemplo, você pode precisar fazer isso se você exportou dados de uma aplicação para um arquivo e quer elaborar esses dados de alguma forma.

Neste exemplo vamos usar um simples arquivo .txt no qual cada linha contém:

  • o nome de uma cidade
  • o número de pessoas que vivem nessa cidade.

Below você pode ver o formato do arquivo de texto, um dois pontos é usado para separar cada cidade do número de pessoas que vivem nessa cidade:

Istanbul:15,067,724Moscow:12,615,279London:9,126,366... 

Então, como podemos usar um Bash para loop para percorrer o conteúdo desse arquivo?

Primeiro vamos armazenar o nome do arquivo em uma variável

FILENAME="european-cities.txt"

Após isso, vamos usar outra variável e o comando cat para obter todas as linhas do arquivo:

LINES=$(cat $FILENAME)

Aqui estamos usando a substituição de comandos para atribuir a saída do comando cat para as variáveis LINES.

Finalmente o for loop permite passar por cada linha do arquivo:

for LINE in $LINESdo echo "$LINE"done

Do e feito são usados para definir os comandos a serem executados a cada iteração do for loop.

Por exemplo, se tiver um ficheiro com 10 linhas o for loop irá passar por 10 iterações e a cada iteração irá ler uma linha do ficheiro.

O comando echo pode ser substituído por qualquer sequência de comandos baseada no que quer fazer com cada linha do ficheiro.

Aqui está o script final:

#!/bin/bash FILENAME="european-cities.txt"LINES=$(cat $FILENAME)for LINE in $LINESdo echo "$LINE"done

E a saída do script é…

./cities.sh Istanbul:15,067,724Moscow:12,615,279London:9,126,366Saint-Petersburg:5,383,890Berlin:3,748,148Kyiv:3,703,100Madrid:3,223,334Rome:2,857,321Paris:2,140,526Bucharest:2,106,144

Estamos passando a lista para o for loop usando o comando cat.

Isso significa que podemos usar qualquer comando que queremos gerar a LIST para ser passada para o for loop.

Você tem em mente algum outro comando possível?

Além disso, o for loop não é a única opção para criar um loop em um script Bash, outra opção é um loop while.

O que é um contador num Bash For Loop?

Em um loop for você também pode definir uma variável chamada contador. Pode usar um contador para acompanhar cada iteração do laço.

O uso de um contador é muito comum em todas as linguagens de programação. Ele também pode ser usado para acessar os elementos de uma estrutura de dados dentro do loop (este não é o caso do nosso exemplo).

Vamos modificar o programa anterior e definir um contador cujo valor é impresso a cada iteração:

#!/bin/bash FILENAME="european-cities.txt"LINES=$(cat $FILENAME)COUNTER=0for LINE in $LINESdo echo "Counter $COUNTER: $LINE" COUNTER=$((COUNTER+1))done

Como você pode ver eu defini uma variável chamada COUNTER fora do loop do for com seu valor inicial definido como 0.

Então a cada iteração eu imprimo o valor do contador junto com a linha do arquivo.

Depois de fazer isso eu uso o operador aritmético Bash para aumentar o valor da variável COUNTER em 1.

E aqui está a saída do script:

Counter 0: Istanbul:15,067,724Counter 1: Moscow:12,615,279Counter 2: London:9,126,366Counter 3: Saint-Petersburg:5,383,890Counter 4: Berlin:3,748,148Counter 5: Kyiv:3,703,100Counter 6: Madrid:3,223,334Counter 7: Rome:2,857,321Counter 8: Paris:2,140,526Counter 9: Bucharest:2,106,144

Break and Continue in a Bash For Loop

Existem formas de alterar o fluxo normal de um for loop no Bash.

Os dois comandos que permitem fazer isso são break e continue:

  • break: interrompe a execução do for loop e salta para a primeira linha após o for loop.
  • continue: salta para a próxima iteração do for loop.

Salvar um contador definido ajuda-nos a ver o que acontece quando adicionamos break ou continuamos ao nosso script existente.

Deixe começar com break…

I adicionará um comando if baseado no valor do contador. O comando break dentro do if quebra a execução do laço se o contador for igual a 3:

#!/bin/bash FILENAME="european-cities.txt"LINES=$(cat $FILENAME)COUNTER=0for LINE in $LINESdo if ; then break fi echo "Counter $COUNTER: $LINE" COUNTER=$((COUNTER+1))done

E o output é:

Counter 0: Istanbul:15,067,724Counter 1: Moscow:12,615,279Counter 2: London:9,126,366

Como você pode ver o comando break pára a execução do for laço antes de alcançar o comando echo porque COUNTER é 3.

Depois disso, vamos substituir break por continue e ver o que acontece. Vou deixar o resto do código inalterado.

#!/bin/bash FILENAME="european-cities.txt"LINES=$(cat $FILENAME)COUNTER=0for LINE in $LINESdo if ; then continue fi echo "Counter $COUNTER: $LINE" COUNTER=$((COUNTER+1))done

E aqui está a saída para o script:

Counter 0: Istanbul:15,067,724Counter 1: Moscow:12,615,279Counter 2: London:9,126,366

Weird…a saída é a mesma. Porque?

É porque quando o valor do COUNTER é 3 o comando continue salta para a próxima iteração do loop mas não incrementa o valor do contador.

Então na próxima iteração o valor do COUNTER ainda é 3 e o comando continue é executado novamente, e assim por diante para todas as outras iterações.

Para corrigir isto temos de aumentar o valor da variável COUNTER dentro do comando if:

#!/bin/bash FILENAME="european-cities.txt"LINES=$(cat $FILENAME)COUNTER=0for LINE in $LINESdo if ; then COUNTER=$((COUNTER+1)) continue fi echo "Counter $COUNTER: $LINE" COUNTER=$((COUNTER+1))done

Desta vez vemos a saída correcta:

Counter 0: Istanbul:15,067,724Counter 1: Moscow:12,615,279Counter 2: London:9,126,366Counter 4: Berlin:3,748,148Counter 5: Kyiv:3,703,100Counter 6: Madrid:3,223,334Counter 7: Rome:2,857,321Counter 8: Paris:2,140,526Counter 9: Bucharest:2,106,144

Como pode ver “Counter 3: ….” não está impresso no terminal.

Escrevendo um Para Loop em Uma Linha

Antes de terminar este tutorial, vamos ver como podemos escrever um para loop em uma linha.

Esta não é uma prática sugerida considerando que torna o seu código menos legível.

Mas é bom saber como escrever um loop em uma linha, dá mais profundidade ao seu conhecimento de Bash.

A sintaxe genérica para um Bash para loop numa linha é a seguinte:

for i in ; do ; done

Deixamos imprimir o conteúdo do nosso ficheiro de texto com uma linha para loop:

#!/bin/bashFILENAME="european-cities.txt"LINES=$(cat $FILENAME)for LINE in $LINES; do echo $LINE; done

Para simplificar as coisas removi o COUNTER e a instrução if. Se eles estivessem lá a única linha para loop seria muito mais difícil de ler.

Tente ficar longe de uma linha se eles tornam o seu código difícil de ler.

Conclusion

Em conclusão, neste tutorial você aprendeu como:

  1. Armazenar as linhas de um arquivo em uma variável
  2. Utilizar um para loop para passar por cada linha.
  3. Utilizar um contador em um para loop.
  4. Alterar o fluxo de um loop com quebra e continuar.
  5. Escrever um para loop em uma linha.

Faz sentido?

Como vai usar isto?

Deixe-me saber 🙂

Se quiser aprender mais sobre loops em Bash scripting dê uma olhada neste tutorial.

Curso GRATUITO relacionado: Decifrar Bash Scripting

Deixe uma resposta

O seu endereço de email não será publicado.