Este es el segundo artículo de una serie centrada en el scripting de Gnu Bash. En el primer artículo sobre secuencias de comandos de bash, acabamos de crear la secuencia de comandos más simple:comandos simples, uno tras otro. También vimos el uso de algunas variables. Este artículo cubrirá las estructuras de control bash.
Estructuras de control
Como he dicho en el artículo anterior, la pereza es la clave del éxito. Si tengo que ejecutar algunos comandos, un tiempo después los mismos comandos en el mismo orden, cuando llegue la tercera vez, abriré un editor de texto y pegaré esos comandos para guardarlos como un script.
Después de un par de días, ese guión comenzó a crecer, tanto en extensión como en complejidad. Necesito formas de controlar el flujo de ejecución, por ejemplo:
- si algo sucede, haz algo, o si algo no sucede, haz otra cosa;
- mientras algo está sucediendo, hacer algo una y otra vez, o hacer algo una y otra vez;
- o dependiendo del valor de una variable o de lo que suceda, hacer esto o aquello u otro,
- etc
Esto es para lo que están destinadas las estructuras de control de bash (en realidad, en bash o en cualquier otro lenguaje de programación). Pero primero, necesitamos saber acerca de:
Estado de salida
Desde la página de manual de bash:
«El estado de salida de un comando ejecutado es el valor devuelto por la llamada al sistema waitpid o una función equivalente. Los estados de salida se encuentran entre 0 y 255. (…) Un estado de salida de cero indica éxito (o, igual a 'verdadero'). Un estado de salida distinto de cero indica un error (o, igual a 'falso'). (…. Por ejemplo:) Si no se encuentra un comando, el proceso secundario creado para ejecutarlo devuelve un estado de 127. Si se encuentra un comando pero no es ejecutable, el estado de retorno es 126 ».
tl;dr:los estados de salida de 0 significan verdadero , éxito; cualquier otro valor significa falso . Es importante aprender esto porque tomar decisiones de verdadero/falso es verificar el estado de salida de un comando.
Bash almacena el estado de salida del último comando ejecutado en $? variables.
si-entonces-otro
Este es el si pasa algo (algo sucede significa un comando con un estado de salida de cero) hacer algo , o bien hacer otra cosa. La sintaxis es:
if command then command1 command2 ... else commandA commandB ... fi
Como puede ver en la captura de pantalla, se puede escribir en una sola línea, separando cada comando con un punto y coma:
if command; then command1; command2;...; else commandA; commandB;...;fi
Dependiendo de la complejidad del bloque si-entonces, podría ser más fácil de leer o más difícil de leer con el estilo 'oneliner'.
¿Qué sucede si desea ejecutar algún comando si algo sucede? Ejecute otro comando solo si algo más sucede? use la palabra clave elif (si no):
if command then command1 command2 ... elif other_command commandA commandB ... else another block of commands fi
Un bloque if-then-else termina con la palabra clave fi (si está al revés).
Comparación de cadenas y números
¿Recuerdas las variables? con frecuencia el algo sucede es que dependiendo del valor de una variable queramos ejecutar unos comandos u otros.
Para comparar si una cadena es igual a alguna palabra o si un número es menor que otro usamos el comando test . La sintaxis general es:
test expression
Si expresión se omite se considera falso (estado de salida> 0). Si expresión es solo una cadena de texto, es verdad. Esto podría ser complicado, por ejemplo:
$ test false; echo $? 0
No estamos probando el estado de salida del comando falso (hay un comando falso ) pero la cadena false contra nada. La otra forma de ejecutar el comando de prueba es encerrar la expresión entre corchetes. Esta otra forma es más fácil de leer dentro de un bloque if-then-else.
operandos | verdadero si |
expresión | verdadero |
! expresión | false (expresión negada) |
expresiónA -a expresiónB | Y. ambas expresiones son verdaderas |
expresiónA -o expresiónB | O. una de las expresiones es verdadera |
cadena1 =cadena2 | ambas cadenas son iguales |
cadena1 !=cadena2 | las cadenas son diferentes |
int1 -eq int2 | entero1 es igual a entero2 |
int1-ge int2 | int1>=int2 |
int1 -gt int2 | int1> int2 |
int1 -le int2 | int1 <=int2 |
int1 -lt int2 | int1 |
int1 -ne int2 | int1 no es igual a int2 |
-archivo e | el archivo existe |
-d directorio | el archivo existe y es un directorio |