Apuntes mientras aprendo sobre software y computadoras.

programación

Bucles y loops en bash scripting

Entonces, sigo con la tarea de aprender a programar en Bash.

Lo que hoy me interesa hacer es crear un apunte sobre la definición de loop… ese tema que se repite, y se repite, y se repite…

Pero antes de continuar, lo mejor va a ser tratar de definir qué es un loop.

¿Qué es un loop?

Es el momento de dar una definición de loop. O como bien se imaginan, es momento de intentar crear mi propia definición de loop.

Quiero decir, buscándolo en el diccionario encuentro que loop se refiere a: vuelta, bucle, círculo y repetición.

No hay mucho espacio para inventar algo.

Algunos ejemplos en la vida diaria de loop:

– Dar tres vueltas completas al rededor de la manzana.

– Escuchar 25 veces seguidas la misma canción puesta en “repetir”.

– Ver una decena de veces la misma escena de una película.

En teoría el loop puede no tener un límite y puede continuar sin detenerse infinitas veces. Como por ejemplo, mirar una imagen situada entre dos espejos. Ese mismo reflejo se ve dentro del espejo, y asi mismo eso se ve dentro del espejo que se refleja, y luego dentro del reflejo en el espejo, una y otra vez.

Igual que en una de esas pinturas de M.C.Escher por ejemplo.

Así que ya tengo la base de lo que es un loop. Ahora necesito llevar la idea al contexto de shell scripting.

Loops en shell scripting

En este exacto momento no me interesa la posibilidad de un loop infinito.

Si un script se queda enfrascado en ese tipo de loop, el programa va a funcionar sin detenerse hasta quesea cerrado o hasta que resulte en un error que haga detenerse.

Detengamos aquí nuestra definición teórica de loop para verlo ahora aplicado al momento de programar dentro de Bash.

El comando “for”:

Para empezar voy a generar un loop para revisar una lista detntro de un programa programa.

En castellano for puede leerse como la palabra “por” o también como “para”.

Digamos como un ejemplo que tengo la siguiente linea de código:

for i in {1..3}; do
    echo "mostrar esta oración"
done

Lo que quiere decir es: “para i en 1 2 3; hacer”.

La “i” de la primera linea se refiere a “cada elemento de esta secuencia”.

En este caso los elementos son los números enteros en la secuencia”1, 2, 3″. Esto es, por cada fragmento o parte en esa secuencia, el programa va a imprimir en la terminal la frase “mostrar esta oración”.

mostrar esta oración
mostrar esta oración
mostrar esta oración

En este caso el loop tiene tres vueltas.

Pero el loop podría estar revisando otra cosa, por ejemplo strings de texto.

Entiendo que lo importante en este caso es que las vueltas se dan al rededor de una lista, que en esta ocasión yo definí anteriormente.

Por otro lado, la palabra “do” ignifica “hacer” en inglés. Palabras como for, in (en) y do forman parte del vocabulario de la shell.

Breve interrupción:

Otra cosa rápida, puedo utilizar el punto y coma (;) como una forma de separación igual a comenzar una linea nueva.

Por ejemplo, es lo mismo decir

for i in {1..3}; do
    echo "mostrar esta oración"
done

A decir:

for i in {1..3}
  do
    echo "mostrar esta oración"
  done

Casi me olvido, en el loop la sintaxis se cierra con la palabra done que significa “terminado” o “está terminado”. Es en algo similar a lo que hago con el condicional if, solo que en ese caso cierros el bloque usando fi en lugar de done.

Todos los comandos que van a ejecutarse están entre do y done.

Loops utilizando while

Este loop es ligeramente, ligeramente más complejo que el anterior. Digamos primero que while puede traducirse por “mientras tanto”.

Este caso es algo más complejo, porque while continua ejecutando los comandos que le damos (los que aparecen entre do y done)mientras sus argumentos devuelvan cero (mientras resulten verdaderos o no terminen en error).

El loop solamente va a detenerse cuando los argumentos regresen “no cero” (sean falsos, dicho de mi forma simplificada) o cuando nosotros le demos la orden de terminar.

Voy a probar con un ejemplo.

#!/bin/bash

suma=1

while [[ "$suma" -le 5 ]] ; do
    echo "contar menos que cinco"
    ((suma++))
done

Si hago correr este programa while revisa que la variable “count” sea menor que cinco. Al ser esto cierto, devuelve True. Como es verdadera, pasa a ejecutar el comando echo.

Cuando la suma “((count++))” supera cinco, el loop devuelve un valor False y se termina.

Hay otras formas de chequear si las condiciones de un loop son verdaderas o falsas.

Tres declaraciones: until, break y continue

Until

La primera de nuestras palabras clave es until, y significa “hasta qué”. Lo que conseguimos es que el loop se rompa en cuanto el argumento que la acompaña resulte verdadero. De alguna manera es como el anti while:

#!/bin/bash

suma=1

until [[ "$suma" -gt 5 ]]
do
    echo "la suma da menos que cinco"
    ((suma++))
done

En este caso el resultado es similar al anterior utilizando “while”, la frase “menos que cinco” se repite cinco veces.

Segun entiendo, la gran diferencia es que “until” espera a terminar el loop cuando aparezca el primer resultado verdadero. Si resulta verdadero que “count=5” el programa se termina. Hasta ese momento el resto de los resultados salen como falsos, y el programa sigue.

Break

La palabra break puedo traducirla en este caso como “frenar” o “romper”, y hace justamente lo que promete. Causa que el programa frene el loop inmediatamente cuando se topa con que la condición pedida se cumple.

Este puede ser un ejemplo:

#!/bin/bash

suma=1

while [ true ]
do
    echo "La suma da: $suma"
    ((suma++))
    if [ "$suma" -gt 5 ]
    then
        break
    fi
done

En el caso anterior, si la suma del conteo resulta “mayor que cinco” Break detiene el loop.

Continue

Dejo para el final la declaración continue (continuar) que muchas veces se utiliza en conjunto con break.

Lo que se consigue al usarlo es que el loop pase directamente a la rama interna que sigue. Todo esto mantiene los comandos aun entre do y done.

##!/bin/bash

# Definir lista de números
numeros=(2 2 4 5 6)

for i in "${numeros[@]}"
do
  # revisar si el número es par
  if [ $((i % 2)) -eq 0 ]; then
    echo "$i es par"
    continue
  else
    break # Salir del loop
  fi
done

En el ejemplo anterior tenemos una lista de números.

Si resulta verdadero que el número es divisible por dos (el resto es igual a cero), se ejecuta el comando “echo” para escribirnos que el mismo “es par” y continua al siguiente número.

Caso contrario, si el número no es divisible por dos el programa se interrumpe con Break.

Conclusión:

Aunque es posible entender la definición de loop, es difícil encontrarle el lugar correcto dentro del panorama general de programar en Bash.

En especial siendo que estamos empezando con todo esto, y nos estamos sobrecargando de información.

Algo importante de destacar es que la misma idea de loop aparece en otros lenguajes de programación, como por ejemplo Python. El trabajo que estamos haciendo ahora va a rendir nuevos frutos cuando estudiemos otros lenguajes.

Como siempre, me gustaría leer tu opinión en los comentarios.

La seguimos en el próximo apunte.

Leave a Reply