Bash tiene dos formas de hacer bucles:
for
Para recorrer una lista de elementos usamos el bucle for.
for varname in words; do COMMANDS; done
words se expande mediante la división de palabras y la expansión de nombres de archivo (que vimos en el concepto de comillas).
Cada palabra se asigna a varname por turno y se ejecutan los COMMANDS.
Aquí tienes algunos ejemplos que muestran cuándo puede resultar útil el bucle for
Ejecutar algunos comandos sobre un grupo de archivos.
# source all the bash library files in the current directory
for file in ./*.bash; do
source "$file"
done
Ejecutar algún comando en cada uno de los parámetros de un script o de una función.
for arg in "$@"; do
echo "argument: ${arg}"
done
Ejecutar algún comando para cada palabra separada por espacios en la salida de un comando.
for i in $(seq 10); do
echo "${i} squared is $((i * i))"
done
Más adelante veremos algunas advertencias sobre este estilo.
for aritméticoBash sí que tiene un bucle aritmético. Resultará algo familiar para quienes conocen otros lenguajes de programación.
for ((INITIALIZATION; CONDITION; INCREMENT)); do COMMANDS; done
Los paréntesis dobles en bash representan un contexto aritmético (veremos más sobre la aritmética de bash en un concepto posterior).
El ejemplo anterior con seq se puede escribir así
for ((i = 1; i <= 10; i++)); do
echo "${i} squared is $((i * i))"
done
for
Este es un antipatrón que verás a menudo: iterar sobre la salida de cat.
for line in $(cat some.file); do
do_something_with "$line"
done
Esto está mal por dos motivos.
for recorre las palabras del archivo, no las líneas.Como aprendimos en el concepto de comillas, la división de palabras se puede controlar con la variable IFS, y la expansión de nombres de archivo se puede desactivar.
Pero suele ser una solución frágil.
for no es el método adecuado para recorrer las líneas de un archivo.
La forma idiomática de leer un archivo es con un bucle while.
while
Usa while para repetir una secuencia de comandos mientras se cumpla una condición.
while CONDITION_COMMANDS; do COMMANDS; done
Al igual que con if (como aprendimos en el concepto de condicionales), no hay una sintaxis especial para CONDITION_COMMANDS.
El estado de salida de la lista de comandos determinará si es «verdadero» o «falso».
El comando break sale del bucle.
El control continúa con el comando que sigue al terminador done del bucle.
El comando continue salta a la siguiente iteración del bucle.
Como ya se ha mencionado, un bucle while es la forma idiomática de leer un archivo.
while IFS= read -r line; do
do_something_with "$line"
done < some.file
El contenido del archivo se pasa como entrada al bucle con la redirección <.
El comando read devuelve «verdadero» si puede leer una línea completa de su entrada.
Cuando la entrada se agota, o si la última línea no termina en un salto de línea, read devuelve «falso».
La forma realmente idiomática de leer las líneas de un archivo, incluso si la última línea no termina en un salto de línea, es
while IFS= read -r line || [[ -n "$line" ]]; do ...
La opción -r le dice a read que no sustituya secuencias de barra invertida: una barra invertida es un carácter normal.
IFS= asigna el string vacío a IFS solo mientras dura el comando read.
Esto desactiva temporalmente la división de palabras para conservar los espacios en blanco que haya al principio o al final de la línea de texto entrante.
untilLa construcción until repite una secuencia de comandos mientras una condición es falsa.
El bucle se repite hasta que la condición se cumple.
until CONDITION_COMMANDS; do COMMANDS; done
Es poco habitual usar until.
Lo más común es usar un bucle «while not».
while ! CONDITION_COMANDS; do ...
A veces quieres repetir un bucle para siempre. Aquí tienes dos formas de hacerlo.
un bucle while con una condición cuyo estado de salida siempre sea de éxito
while true; do ...
un bucle for aritmético con expresiones vacías
for ((;;)); do ...
No existe una construcción do-while explícita, pero puedes conseguir el mismo efecto:
while true; do
COMMANDS
if END_CONDITION; then
break
fi
done