La shell tiene un conjunto de estructuras de control, que son muy parecidos a otros lenguajes de programación. En las siguientes secciones, las sentencias son las series de comandos para ejecutar cuando, mientras o hasta que se cumpla la condición.
if
La sentencia if
es muy sencilla, comprueba el resultado de un comando y después ejecuta condicionalmente un grupo de sentencias (statements):
if
se suele usar para realizar una pregunta y para tomar posteriormente una decisión basándose en la respuesta:
llamamos a este script saludo y nos dá la siguiente salida:
no olvidemos dar permiso de ejecución a nuestro archivo con el comando chmod +x saludo
y ejecutarlo con ./saludo
.
Este script usa el comando [
para comprobar los contenidos de la variable pregunta
. El resultado lo evalúa el comando if
, que después permite que se ejecuten diferentes lineas de código.
elif
Desafortunadamente, este script tan sencillo genera muchos problemas. Uno de ellos es que interpreta que toda respuesta que no sea si
significa no
. Podemos evitarlo utilizando la construcción elif
, que le permite añadir una segunda comprobación que se realizará cuando se ejecute la parte else
de if
.
Comprobar usando elif
Se puede modificar el script anterior para que envíe un mensaje de error si el usuario escribe cualquier otra diferente a si
o no
. Hágalo reemplazando else
por elif
y añada después otra condición:
Ahora el resultado obtenido es un poco más profesional:
El funcionamiento es muy parecido al del ejemplo anterior, pero ahora el comando elif
comprueba la variable de nuevo si la primera condición if
no es verdadera. Si ninguna de las comprobaciones concluye con éxito, se muestra un mensaje de error y el script existe con el valor 1
, que el usuario puede usar en un programa de llamada para comprobar si el script tuvo éxito.
Un problema con las variables
Si ejecutamos otra vez nuestro script comprobamos que si presionamos la tecla ENTER en vez de responder a la pregunta, obtendremos un mensaje de error:
El problema lo vemos en la primera clausula if
. Cuando if
comprobó la variable pregunta
al pulsar ENTER, la trató como una cadena en blanco. Por eso, la clausula if
tenía esta apariencia:
que no es una condición válida. Para evitarlo, debemos usar las comillas («») alrededor de la variable:
Después, una variable vacía proporcionará la comprobación válida:
El nuevo script tendría esta apariencia:
Ahora, podemos presionar INTRO para responder a la pregunta.
Bash permite eliminar la nueva línea usando el comando echo -n "Lo siento, no reconozco "$pregunta". Introduce si o no"
.
for
Este comando hace bucles a través de varios valores, puede ser cualquier conjunto de cadenas. Se puede enumerar en el programa o, más comúnmente, en el resultado de una expansión shell de los nombres de archivo.
La sintaxis es sencilla:
Uso del bucle for con cadenas fijadas
Los valores suelen ser cadenas, de manera que podemos escribir:
Que generará la siguiente salida:
Si recordamos anteriormente si encerramos entre comillas los días de la semana se interpretará como si fuera una cadena única siendo uno de los modos de conseguir almacenar los espacios de una variable:
Vemos el resultado:
Cómo funciona
Este ejemplo crea la variable semana
y le asigna un valor diferente cada vez alrededor del bucle for. Como la shell considera que todas las variables contienen cadenas por defecto, es tan válido usar una cadena alfanumérica como numérica.
Usar un bucle for con expansión de comodín
Se suele usar el bucle for
con una expansión shell de los nombres de archivo. Esto significa usar un comodín para el valor de la cadena y con esto permitimos a la shell que complete todos los valores en el tiempo de ejecución.
Este script usa la expansión shell, * expandiendo los nombres del directorio actual. Se emplea uno a uno como la variable $file
dentro del bucle for
.
En este ejemplo ponemos de manifiesto el uso de la sintaxis $
(command), que estudiaremos detalladamente más adelante. Básicamente, la lista de parámetros del comando for
la proporciona la salida del comando que se encuentra dentro de la secuencia $()
.
La shell expande c*
para proporcionar los nombres de todos los archivos que cumplan este patrón.
while
Como por defecto todos los valores shell se consideran cadenas, el bucle for
es adecuado para serpentear a través de una serie de cadenas, pero no resulta útil cuando no se sabe de antemano cuántas veces desea ejecutar el bucle.
Cuando tenga que repetir una secuencia de comandos, y no conozca previamente el número de veces que deberá ejecutarse, puede usar el bucle while
, que tiene la siguiente sintaxis:
Crearemos como ejemplo un programa bastante sencillo que comprobará una contraseña:
Ejecutamos el script y tendremos:
Evidentemente no se tratas de un modo muy seguro para solicitar una contraseña, pero nos sirve para mostrar la sentencia while
. Las sentencias que se encuentran entre do
y done
se ejecutan constantemente hasta que la condición deja de ser verdadera. En este caso, está comprobando si el valor de pass
es igual a atika
. El bucle seguirá hasta que $pass
equivalga a atika
. Después seguirá ejecutando el script de la sentencia que va justo detrás de done
.
until
La sentencia until tiene la siguiente sintaxis:
Es muy similar al bucle while
, pero con el test de condición invertido. En otras palabras, el bucle continúa hasta que la condición es verdadera, no mientras la condición sea verdadera.
case
La construcción case
es un poco más compleja que las que hemos visto hasta el momento. La sintaxis es:
La construcción case
permite comparar los contenidos de una variable con los patrones de un modo muy sofisticado y luego le permite la ejecución de diferentes sentencias, dependiendo del patrón comparado. Es mucho más sencillo que la opción alternativa para comparar muchas condiciones, que quería usar múltiples sentencias if
, else
y elif
.
La capacidad de comprobar varios patrones y de ejecutar después varias sentencias relacionadas hace que la construcción case
sea un buen método para gestionar los datos de entrada del usuario. El mejor modo para comprobar cómo funciona case
es mediante un ejemplo que desarrollaremos en tres secciones, mejorando con cada uno la correspondencia de patrones.
Caso I: datos de entrada del usuario
Podemos escribir una nueva versión del script saludo que hace la comprobación de la entrada del usuario mediante la construcción case que será un poco más selectivo y comprensivo ante los datos inesperados.
Cómo funciona
Al ejecutar la sentencia case
, adopta los contenidos de respuesta y los compara uno a uno con todas las cadenas. En cuanto una cadena se corresponda con los datos de entrada, el comando case ejecuta el código que aparece tras )
y finaliza.
El comando case
realiza la expansión normal de las cadenas que está usando para realizar la comparación. por eso puede especificar parte de una cadena seguida por el comodín *
. si usa un único *
, se corresponderán todas las cadenas posibles. Coloque otro asterisco tras las cadenas de correspondencia para que la sentencia case
finalice con alguna acción preestablecida si no se corresponde ninguna cadena. Esto es posible porque la sentencia case
compara las cadenas una a una. No busca el mejor resultado, sino la primera correspondencia. La condición predeterminada suele ser la condición imposible, por eso el uso de *
puede ayudar a localizar y solucionar los errores del scripts.
Caso II: unión de patrones
La construcción case
anterior es mucho más elegante que la versión múltiple de la sentencia if
, pero al unir los patrones, puede obtener una versión mucho más organizada:
Cómo funciona
Con este script usamos cadenas múltiples con cada entrada de case
, de manera que case
comprueba muchas cadenas diferentes para cada posible sentencia. Esto hace que el script sea mucho más breve y que, con la práctica, resulte más fácil leerlo. Este código muestra también cómo se puede usar el comodín *
, aunque puede hacer corresponder patrones no deseanos. Por ejemplo, si el usuario introduce nose
, dicha entrada se corresponderá con n*
y aparecerá Buenas tardes
, que no es el comportamiento deseado. Tenga en cuenta que el comodín *
no funciona entre comillas.
Caso III: ejecutar sentencias múltiples
Finalmente para poder volver a usar el script, necesitamos un valor de salida diferente cuando se use el patrón predeterminado, porque no se comprendieron los datos de entrada:
Cómo funciona
Para mostrar otro modo de correspondencia de patrones, este código modifica el modo de correspondencia del caso no
. También muestra cómo se debe ejecutar múltiples sentencias para cada patrón de la sentencia case
. Debemos colocar las correspondencias más explícitas en primer lugar y las más generales en último lugar. Esto es importante porque case
ejecuta la primera correspondencia que encuentra, no la más apropiada. Si pone *)
en primer lugar, siempre habrá correspondencia, independientemente de los datos de entrada.
Debe estar conectado para enviar un comentario.