Bucle a través de las líneas de un archivo: explicación del bucle for de Bash

Quiero hacer un bucle a través de las líneas de un archivo con un script de Bash y una de las formas de hacerlo es usando un bucle for.

¿Qué es un bucle for?

Un bucle for es una de las construcciones de programación más comunes y se utiliza para ejecutar un bloque de código dado un conjunto de elementos en una lista. Por ejemplo, digamos que quieres escribir un programa que imprima el número de personas que viven en las 10 mayores ciudades europeas. El programa puede utilizar un bucle for para recorrer cada ciudad de la lista e imprimir el número de personas de esa ciudad.

La lógica que se ejecuta es cada vez la misma y lo único que cambia es la ciudad.

A continuación puedes ver la sintaxis genérica de un bucle for de Bash:

for item in do command1 command2 ... commandNdone

La lista puede ser, por ejemplo:

  • un rango de números.
  • una secuencia de cadenas separadas por espacios.
  • la salida de un comando de Linux (por ejemplo, el comando ls).

Los N comandos entre do y done se ejecutan para cada elemento de la lista.

Bucle for en Bash

En este artículo aprenderás a utilizar el bucle for en Bash y concretamente a recorrer las líneas de un archivo.

¿Pero por qué lo harías? Recorrer las líneas de un archivo?

Por ejemplo, podrías necesitar hacerlo si has exportado datos de una aplicación a un archivo y quieres elaborar esos datos de alguna manera.

En este ejemplo usaremos un simple archivo .txt en el que cada línea contiene:

  • el nombre de una ciudad
  • el número de personas que viven en esa ciudad.

Abajo puedes ver el formato del fichero de texto, se utilizan dos puntos para separar cada ciudad del número de personas que viven en esa ciudad:

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

Entonces, ¿cómo podemos utilizar un bucle for de Bash para recorrer el contenido de este fichero?

Primero almacenaremos el nombre del archivo en una variable

FILENAME="european-cities.txt"

Después, utilizaremos otra variable y el comando cat para obtener todas las líneas del archivo:

LINES=$(cat $FILENAME)

Aquí estamos utilizando la sustitución de comandos para asignar la salida del comando cat a las variables LINES.

Finalmente el bucle for permite recorrer cada línea del fichero:

for LINE in $LINESdo echo "$LINE"done

Do y done se utilizan para definir los comandos a ejecutar en cada iteración del bucle for.

Por ejemplo, si tienes un fichero con 10 líneas el bucle for pasará por 10 iteraciones y en cada iteración leerá una línea del fichero.

El comando echo puede ser sustituido por cualquier secuencia de comandos en función de lo que quieras hacer con cada línea del fichero.

Aquí está el script final:

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

Y la salida del script es…

./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 pasando la lista al bucle for usando el comando cat.

Esto significa que podemos usar cualquier comando que queramos para generar la LISTA que se pasará al bucle for.

¿Tienes en mente algún otro comando posible?

Además, el bucle for no es la única opción para crear un bucle en un script Bash, otra opción es un bucle while.

¿Qué es un contador en un bucle for de Bash?

En un bucle for también se puede definir una variable llamada contador. Puede utilizar un contador para rastrear cada iteración del bucle.

El uso de un contador es muy común en todos los lenguajes de programación. También se puede utilizar para acceder a los elementos de una estructura de datos dentro del bucle (no es el caso de nuestro ejemplo).

Modifiquemos el programa anterior y definamos un contador cuyo valor se imprima en cada iteración:

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

Como puedes ver he definido una variable llamada CONTADOR fuera del bucle for con su valor inicial fijado en 0.

Después en cada iteración imprimo el valor del contador junto con la línea del fichero.

Después de hacer esto uso el operador aritmético de Bash para aumentar el valor de la variable CONTADOR en 1.

Y aquí está la salida del 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 y Continue en un bucle for de Bash

Hay formas de alterar el flujo normal de un bucle for en Bash.

Las dos sentencias que permiten hacerlo son break y continue:

  • break: interrumpe la ejecución del bucle for y salta a la primera línea después del bucle for.
  • continue: salta a la siguiente iteración del bucle for.

Haber definido un contador nos ayuda a ver qué ocurre cuando añadimos break o continue a nuestro script existente.

Comencemos con break…

Añadiré una sentencia if basada en el valor del contador. La sentencia break dentro del if rompe la ejecución del bucle si el contador es 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

Y la salida es:

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

Como puedes ver la sentencia break detiene la ejecución del bucle for antes de llegar al comando echo porque el CONTADOR es 3.

Después, sustituyamos break por continue y veamos qué pasa. Dejaré el resto del código sin cambios.

#!/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

Y aquí está la salida del script:

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

Raro… la salida es la misma. ¿Por qué?

Es porque cuando el valor del CONTADOR es 3 la sentencia continue salta a la siguiente iteración del bucle pero no incrementa el valor del contador.

Así que en la siguiente iteración el valor del CONTADOR sigue siendo 3 y se vuelve a ejecutar la sentencia continue, y así para el resto de iteraciones.

Para arreglar esto tenemos que aumentar el valor de la variable COUNTER dentro de la sentencia 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

Esta vez vemos la salida 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 puedes ver «Counter 3: ….» no se imprime en el terminal.

Escribiendo un bucle for en una línea

Antes de terminar este tutorial, vamos a ver cómo podemos escribir un bucle for en una línea.

Esta no es una práctica sugerida teniendo en cuenta que hace que su código sea menos legible.

Pero es bueno saber cómo escribir un bucle en una línea, da más profundidad a su conocimiento de Bash.

La sintaxis genérica para un bucle for de Bash en una línea es la siguiente:

for i in ; do ; done

Imprimamos el contenido de nuestro archivo de texto con un bucle for de una línea:

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

Para simplificar las cosas he eliminado el COUNTER y la sentencia if. Si estuvieran ahí el bucle for de una línea sería mucho más difícil de leer.

Intenta mantenerte alejado de las frases de una línea si hacen que tu código sea difícil de leer.

Conclusión

En conclusión, en este tutorial has aprendido a:

  1. Guardar las líneas de un archivo en una variable
  2. Utilizar un bucle for para recorrer cada línea.
  3. Utilizar un contador en un bucle for.
  4. Cambiar el flujo de un bucle con break y continue.
  5. Escribir un bucle for en una línea.

¿Tiene sentido?

¿Cómo vas a usar esto?

Házmelo saber 🙂

Si quieres aprender más sobre bucles en Bash scripting echa un vistazo a este tutorial.

Curso GRATIS relacionado: Descifrar Bash Scripting

Deja una respuesta

Tu dirección de correo electrónico no será publicada.