Conceptos Básicos de BASH - Parte 6: Bucles y Funciones

La introducción a la programación termina con los aspectos finales de la programación con bucles y funciones. Para ver más sobre BASH, la línea de comandos, scripts BASH interesantes y las funciones de la línea de comandos, puede recurrir a los scripts BASH y analizarlos con el nuevo conocimiento adquirido en las últimas partes de esta serie de Conceptos Básicos de BASH. Cubrimos los bucles y las funciones brevemente al principio, pero como son tan importantes, en este artículo los analizaremos con más detalle y veremos cómo se utilizan.

Bucles

BASH tiene tres estructuras básicas de bucle: el bucle while, el bucle until y el bucle for que habíamos visto con anterioridad. Entonces, ¿dónde usamos cada bucle? Los bucles while se utilizan siempre y cuando una expresión se evalúa como verdadera. Veamos primero un script que nos abre cuatro terminales para evitar trabajos repetitivos:

4terminals.sh

#!/bin/bash
# This script opens 4 terminal windows
i="0"

while [ $i -lt 4 ] #test condition and while statement
do
#open terminal and background it until 4 windows are open
mate-terminal &
i=$[$i+1] #increment counter
done
Si fijas tu variable como verdadera, el bucle se ejecuta de forma indefinida. Puedes salir de él con ctrl-c o una declaración break, que vamos a tratar a continuación. Incrementar el contador, ((i ++)), también es una forma válida de hacerlo. ¡Evita los errores "off-by-one" o "fencepost"! Comprueba cuándo usar lt o le, larger than o larger o egual, usando primero un ejemplo simple. Los bucles until se ejecutan hasta que test se vuelve verdadera. Al cambiar la declaración en el script anterior a until y al cambiar el test, podemos lograr el mismo resultado:

4terminals2.sh

#!/bin/bash
# This script opens 4 terminal windows
i="0"

#test condition and until statement
until [ $i -ge 4 ]
do
#open terminal and background it until 4 windows are open
mate-terminal &
((i++)) #increment counter
done
Al adoptar la declaración y test, logramos resultados idénticos. ¿Por qué usar una declaración diferente, entonces? Simplemente se trata de usar un código limpio y elegante. Tú eliges lo que te sea más fácil de leer, codificar y entender en una situación particular. "Don’t touch the paint until it’s dry" es más fácil de entender que "Don’t touch the paint while it’s not dry", o incluso "Don’t touch the paint while it is wet". El bucle for ya estaba cubierto; la estructura for ... do ... done ya debería estar clara. Con for i en {a..b}, también podemos definir rangos de valores. Un script con un rango se vería así:

4terminalswithrange.sh

#!/bin/bash
# simple range in for loops
for i={1..4}

do
mate-terminal &
done

echo "Preparations completed!"
Ten cuidado de no incluir espacios dentro de los corchetes; de lo contrario, se verá como una lista de elementos. Si el primer número es más grande que el segundo, el conteo aparecerá abajo en lugar de arriba; además, un número añadido después de dos puntos como {a..b..c} se incrementará con el tamaño de c. Los bucles for son increíblemente útiles cuando queremos procesar conjuntos de archivos, como ya hemos visto en los ejemplos anteriores.

Sin embargo, hay otras formas de controlar los bucles y scripts: los comandos break, continue y select. Imagina que quieres escribir un script para hacer una copia de seguridad de un conjunto de archivos copiándolos en otro lugar, pero solo cuando el disco está por debajo del 95% de su capacidad:

backupfiles.sh

#!/bin/bash
# make a backup of files in dir
# usage: backupfiles.sh dir
for i in $1/*
do
level=$( df $1 | tail -1 | awk '{ print $5 }' | sed 's/%//' )
if [ $level -gt 95 ]
then
echo Low disk space 1>&2
break
fi
cp $i $1/backup/
done
Con continue, puede detener la ejecución del código dentro de un bucle y saltar al siguiente ciclo. Si queremos ampliar el script de copia de seguridad, quizás podemos introducir un bloque de código para que nos avise de los archivos con derechos de lectura insuficientes, que por tanto no se pueden copiar:
for i in $1/*
do
if [ ! -r $i ]
then
echo $i not readable 1>&2
continue
fi
cp $i $1/backup/
done
El comando select hace posible disponer de un simple menú para la entrada de datos con las opciones proporcionadas: La sistaxis es “select var in ; do ; done”. No hay comprobación de errores; una entrada no válida deja var vacío. El bucle termina con una declaración break o una señal EOF, y el prompt puede cambiarse modificando la variable del sistema PS3. El siguiente código muestra una aplicación práctica:

odroidid.sh

#!/bin/bash
# Odroid model selector

model='HC1 HC2 XU4 C1+ C2 Quit'

PS3='Select Odroid type: '

select name in $model
do
if [ $model == 'Quit' ]
then
break
fi
echo Your model is Odroid $model
done

echo End.

Functiones

Las funciones son formas de reutilizar el código, ya sea en scripts o en su archivo .bashrc, donde ya las encontramos. Las funciones son los elementos finales de la programación de los que vamos hablar. Con las funciones, éstas debemos definirlas antes de llamarlas en BASH. Una definición de función es:

function function_name {

}

or alternatively

function_name() {

}
Como de costumbre, se accede a los argumentos pasados de la función con $1, $2 y así sucesivamente. Las funciones BASH proporcionan un estado de retorno, al usar return n en la función, donde n es cualquier número, y se recupera con $? desde el script de llamada. Tradicionalmente, el estado de retorno 0 indica una ejecución sin problemas.

Si una función NO devuelve un resultado, puede solucionarlo utilizando la sustitución de comandos con $ (function_name) y haciendo que la función muestre solo el resultado. Luego, puede asignar una variable var = $ (function_name) con el valor de la función que muestra normalmente.

Miscelánea

Echemos un vistazo a algunos scripts BASH interesantes que utilizan los tipos de bucles y funciones. Una colección bastante interesante y actualizada es Bash Snippets de Alexander Epstein. Puedes instalarlos con los siguientes comandos, o directamente con git clone, tal y como se menciona en las instrucciones en la página web de Github:

$ sudo add-apt-repository ppa:navanchauhan/bash-snippets
$ sudo apt update
$ sudo apt install bash-snippets
Quisiera ver dos de estos fragmentos más de cerca: geo y qrify. Por favor analiza los scripts en tu editor favorito. Son ejemplos muy buenos de scripts que ejemplifican cómo usar lo que hemos aprendido hasta ahora. Puedes encontrarlos con los comandos habituales, find / -iname ‘*qrify*’ 2>/dev/null finds qrify.sh en cualquier lugar de tu sistema, independientemente de tu método de instalación. Primero, echemos un vistazo a Geo, como se muestra en la Figura 1.

Figura 1 - geo

La página de ayuda de geo muestra lo que puedes hacer con él: un script muy útil para obtener la IP LAN y WAN de tu ODROID, información sobre tu red, así como información de geolocalización. Un poco más ostentoso y menos mundano es qrify:

Con una sintaxis como la del ejemplo, qrify “WIFI:T:WPA;S:mynetwork;P:mypass;;”, puedes sustituir mynetwork y mypass por tu nombre y contraseña WLAN y hacer que el QR sea leído por cualquier smartphone moderno. Cuando lo guardes como .png a través de las opciones de qrify, puede imprimirlo o mostrarlo en pantalla. Un pequeño SBC equipado con una pantalla HAT de papel electrónico podría ser un proyecto bastante interesante para distribuir los códigos WLAN en un mostrador de recepción. En la siguiente parte, trataremos comandos más útiles para aprovechar al máximo tu ODROID. ¡Mantente al tanto!

Referencias https://github.com/alexanderepstein/Bash-Snippets

Be the first to comment

Leave a Reply