Imprimir

Manual de Bash: bucles y estructuras

Anidar bucles

En general, en Bash es posible anidar todo tipo de bucles, estructuras y condiciones.

Estructuras condicionales if

Las estructuras condicionales if permiten que nuestros scripts se comporten de una forma u otra según la condición que especifiquemos, siendo condición un comando test. La sintaxis es:

if condicion1; then
    Bloque1
elif condicion2; then
    Bloque2
else
    Bloque3
fi

En el siguiente ejemplo pedimos al usuario un número que se almacena en la variable $input. Dependiendo de si el número es menor, igual o mayor que 5, el script se comporta de una forma u otra. Si el usuario no introduce nada o introduce una cadena de texto, se ejecutará lo que hay tras else, pues ninguna de las condiciones anteriores se cumple.

#!/bin/bash
echo "Introduzca un numero: "
read input
if [ $input -lt 5 ]; then
    echo "El numero era menor que 5"
elif [ $input -eq 5 ]; then
    echo "El numero era 5"
elif [ $input -gt 5 ]; then
    echo "El numero era mayor que 5"
else
    echo "No introdujo un numero"
fi

En el siguiente ejemplo, primero comprobamos que nos han pasado dos argumentos (el archivo donde buscar y la cadena de búsqueda): si no es así, le indicamos al usuario cómo debe ejecutar el script y salimos. A continuación comprobamos que el archivo existe: si no es así, advertimos y salimos. Una vez verificadas estas dos condiciones, mediante cat y el pipe, grep cuenta el número de veces que el valor de $BUSQUEDA está en el archivo, que queda guardado en $NUM_VECES.

#!/bin/bash
if [ $# -ne 2 ]; then
    echo "Necesito dos argumentos, el primero"
    echo "es el archivo donde debo buscar y"
    echo "el segundo es lo que quieres que busque."
    echo " "
    echo "Uso: $0 <archivo> <patron_busqueda>"
    echo " "
    exit
fi
ARCHIVO=$1
BUSQUEDA=$2
if [ ! -e $ARCHIVO ]; then
    echo "El archivo no existe"
    exit
fi
NUM_VECES='cat "$ARCHIVO" | grep --count "$BUSQUEDA"'
if [ $NUM_VECES -eq 0 ]; then
    echo "El patron de busqueda \"$BUSQUEDA\" no fue encontrado"
    echo "en el archivo $ARCHIVO "
else
    echo "El patron de busqueda \"$BUSQUEDA\" fue encontrado"
    echo "en el archivo $ARCHIVO $NUM_VECES veces"
fi

Estructura case

La estructura case sirve para actuar de una u otra manera en función del valor de una variable: esto podríamos hacerlo con if, pero case es más eficiente y cómodo. La sintaxis es:

case $VARIABLE in
    valor1)
        Bloque 1
        ;;
    valor2)
        Bloque 2
        ;;
    ...
    *)
        Bloque default
        ;;
esac

Si $VARIABLE no coincide con ninguno de los valores valor1, valor2... sí coindirá con el comodín *, ejecutándose el Bloque default. Veamos un ejemplo:

#!/bin/bash
if [ $# -lt 1 ]; then
    echo "Error. Esperaba al menos un parametro"
    exit 1
fi
case $1 in
    windows)
        echo "El logo de windows es una ventana"
        exit 0
        ;;
    mac)
        echo "El logo de mac es una manzana"
        exit 0
        ;;
    linux)
        echo "El logo de linux es un pinguino"
        exit 0
        ;;
    *)
        echo "Logo sin definir"
        exit 1
        ;;
esac

Bucles for

El bucle for viene a solucionar el problema de "Para cada uno de los elementos siguientes, quiero que mi script haga esto". El bucle for ejecuta las sentencias de Bloque tantas veces como elementos haya en LISTA: la primera vez VARIABLE valdrá el primer elemento de la lista, la segunda vez VARIABLE valdrá el segundo elemento de la lista, y así sucesivamente. El elemento LISTA del bucle for puede ser una variable que contenga una lista de elementos:
lista = "pedro pepe juan jose"
for i in $lista; do
... una lista de elementos:
for i in pedro pepe juan jose; do
... una lista de archivos dada utilizando comodines:
for i in $DIR/.*; do
... o un comando tal que su salida sea una lista de elementos:
for i in 'ls'; do
La sintaxis del bucle for es:

for VARIABLE in LISTA ; do
    Bloque
done

Veamos un ejemplo. Si ejecutamos el siguiente script:

#!/bin/bash
for i in pedro pepe juan jose; do
    echo "Hola $i"
done

obtenemos:

Hola pedro
Hola pepe
Hola juan
Hoja jose

El siguiente ejemplo lista los archivos y directorios ocultos. Una vez comprobado que la cadena que se le ha pasado como argumento no tiene longitud cero, que existe y que es un directorio, lista cada archivo que pertenezca a la lista, es decir, que verifique que su primer carácter es un punto (.):

#!/bin/bash
DIR=$1
if [ -z $DIR ]; then
    echo "El primer argumento debe tener longitud mayor que 0"
    exit 1
fi
if [ ! -d $DIR ]; then
    echo "El directorio debe existir y ser un directorio"
    exit 1
fi
for i in $DIR/.*; do
    echo "Encontrado el elemento oculto $i"
done
echo "Finalizado"

En el bucle for podemos usar break para salir del bucle en cualquier momento.

Bucles while

El otro tipo de bucle posible en los scripts de bash es el bucle while. Este bucle viene a solucionar el problema de "quiero que mi script haga esto mientras que se dé esta condición". Su sintaxis es:

while test CONDICION; do
    Bloque
done

En el siguiente ejemplo la condición para que el bucle se siga ejecutando es "que $j valga menos de 10", y en cada ciclo sumamos 1 a la variable $j:

#!/bin/bash
j=0
while [ $j -lt 10 ]; do
    echo "j vale $j"
    j=$[$j+1]
done

En el bucle while también podemos usar break para salir del bucle en cualquier momento. En el siguiente ejemplo la condición se cumple siempre (test 1 siempre retornará TRUE), pero break hará que termine el bucle cuando el número introducido sea igual a $MINUM.

#!/bin/bash
MINUM=8
while [ 1 ]; do
    echo "Introduzca un numero: "
    read USER_NUM
    if [ $USER_NUM -lt $MINUM ]; then
        echo "El numero introducido es menor que el mio"
        echo " "
    elif [ $USER_NUM -gt $MINUM ]; then
        echo "El numero introducido es mayor que el mio"
        echo " "
    elif [ $USER_NUM -eq $MINUM ]; then
        echo "Acertaste: Mi numero era $MINUM"
        break
    fi
done
echo "El script salio del bucle. Finalizado."

Deja un comentario