Cómo atrapar errores en Bash Scripts en Linux

fatmawati achmad zaenuri / Shutterstock.com

De forma predeterminada, un script Bash en Linux informará un error pero seguirá ejecutándose. Le mostramos cómo manejar los errores usted mismo para que pueda decidir qué debe suceder a continuación.

Índice de contenidos
  1. Manejo de errores en scripts
  2. Detección del estado de salida
  3. Usar set para forzar una salida
  4. Usar trap con errores
  5. Un consejo final

Manejo de errores en scripts

El manejo de errores es parte de la programación. Incluso si escribe un código impecable, aún puede encontrarse con condiciones de error. El entorno de su computadora cambia con el tiempo, a medida que instala y desinstala software, crea directorios y realiza mejoras y actualizaciones.

Por ejemplo, una secuencia de comandos que solía ejecutarse sin problemas puede tener dificultades si cambian las rutas del directorio o si se modifican los permisos en un archivo. La acción predeterminada del shell Bash es imprimir un mensaje de error y continuar con la ejecución del script. Este es un valor predeterminado peligroso.

Si la acción que falló es crítica para algún otro procesamiento o acción que ocurra más adelante en su secuencia de comandos, esa acción crítica no tendrá éxito. Lo desastroso que resulte depende de lo que el script intente hacer.

Un esquema más robusto detectaría errores y permitiría que el script funcionara si necesita apagarse o tratar de remediar la condición de falla. Por ejemplo, si falta un directorio o un archivo, puede ser satisfactorio que el script los vuelva a crear.

Si el script ha encontrado un problema del que no puede recuperarse, puede cerrarse. Si el script tiene que cerrarse, puede tener la oportunidad de realizar cualquier limpieza necesaria, como eliminar archivos temporales o escribir la condición de error y el motivo del cierre en un archivo de registro.

Detección del estado de salida

Los comandos y programas generan un valor que se envía al sistema operativo cuando terminan. Esto se llama su estado de salida. Tiene un valor de cero si no hubo errores, o algún valor distinto de cero si ocurrió un error.

Podemos verificar el estado de salida, también conocido como código de retorno, de los comandos que usa el script y determinar si el comando fue exitoso o no.

En Bash, cero equivale a verdadero. Si la respuesta del comando no es verdadera, sabemos que ha ocurrido un problema y podemos tomar las medidas apropiadas.

Copie este script en un editor y guárdelo en un archivo llamado "bad_command.sh".

#!/bin/bash

if ( ! bad_command ); then
  echo "bad_command flagged an error."
  exit 1
fi

Deberá hacer que el script sea ejecutable con el chmod dominio. Este es un paso que se requiere para hacer que cualquier secuencia de comandos sea ejecutable, por lo que si desea probar las secuencias de comandos en su propia máquina, recuerde hacer esto para cada una de ellas. Sustituya el nombre del script apropiado en cada caso.

chmod +x bad_command.sh

Haciendo un script ejecutable usando chmod

Cuando ejecutamos el script, vemos el mensaje de error esperado.

./bad_command.sh

Comprobación del estado de salida de un comando para determinar si ha habido un error

No existe un comando como "bad_command", ni es el nombre de una función dentro del script. No se puede ejecutar, por lo que la respuesta es no cero. Si la respuesta no es cero, el signo de exclamación se usa aquí como la respuesta lógica. NOT operador — el cuerpo del if se ejecuta la sentencia.

En una secuencia de comandos del mundo real, esto podría terminar la secuencia de comandos, lo que hace nuestro ejemplo, o podría intentar remediar la condición de falla.

Podría parecerse a la exit 1 la línea es redundante. Después de todo, no hay nada más en el script y terminará de todos modos. pero usando el exit El comando nos permite pasar un estado de salida al shell. Si alguna vez se llama a nuestro script desde un segundo script, ese segundo script sabrá que este script encontró errores.

Puedes usar la lógica OR operador con el estado de salida de un comando, y llame a otro comando o una función en su secuencia de comandos si hay una respuesta distinta de cero del primer comando.

command_1 || command_2

Esto funciona porque el primer comando se ejecuta OR el segundo. El comando más a la izquierda se ejecuta primero. Si tiene éxito, el segundo comando no se ejecuta. Pero si falla el primer comando, se ejecuta el segundo comando. Entonces podemos estructurar un código como este. Esto es "lógico-o./sh".

#!/bin/bash

error_handler()
{
  echo "Error: ($?) $1"
  exit 1
}

bad_command || error_handler "bad_command failed, Line: ${LINENO}"

Hemos definido una función llamada error_handler . Esto imprime el estado de salida del comando fallido, contenido en la variable $? y una línea de texto que se le pasa cuando se llama a la función. Esto se lleva a cabo en la variable $1. La función finaliza el script con un estado de salida de uno.

El script intenta ejecutarse bad_command que obviamente falla, por lo que el comando a la derecha de la lógica OR operador, ||, es ejecutado. Esto llama el error_handler función y pasa una cadena que nombra el comando que falló y contiene el número de línea del comando que falla.

Ejecutaremos la secuencia de comandos para ver el mensaje del controlador de errores y luego verificaremos el estado de salida de la secuencia de comandos usando echo.

./logical-or.sh
echo $?

Uso del operador lógico OR para llamar al controlador de errores en un script

Nuestro pequeño error_handler La función proporciona el estado de salida del intento de ejecución. bad_command, el nombre del comando y el número de línea. Esta es información útil cuando está depurando un script.

El estado de salida del script es uno. El estado de salida 127 informado por error_handler significa "comando no encontrado". Si quisiéramos, podríamos usar eso como el estado de salida del script pasándolo al exit dominio.

Otro enfoque sería ampliar error_handler para verificar los diferentes valores posibles del estado de salida y realizar diferentes acciones en consecuencia, utilizando este tipo de construcción:

exit_code=$?

if [ $exit_code -eq 1 ]; then
  echo "Operation not permitted"

elif [ $exit_code -eq 2 ]; then
  echo "Misuse of shell builtins"
.
.
.
elif [ $status -eq 128 ]; then
  echo "Invalid argument"
fi

Usar set para forzar una salida

Si sabe que quiere que su secuencia de comandos se cierre siempre que haya un error, puede forzarlo a que lo haga. significa que renuncia a la posibilidad de cualquier limpieza, o también de cualquier daño adicional, porque su secuencia de comandos finaliza tan pronto como detecta un error.

Para hacer esto, use el set comando con el -e (error) opción. Esto le dice a la secuencia de comandos que salga cada vez que un comando falla o devuelve un código de salida mayor que cero. También, usando el -E La opción garantiza que la detección de errores y el reventado funcionen en las funciones de shell.

Para capturar también variables no inicializadas, agregue el -u (desarmado) opción. Para asegurarse de que se detecten errores en las secuencias canalizadas, agregue el -o pipefail opción. Sin esto, el estado de salida de una secuencia canalizada de comandos es el estado de salida del final comando en la secuencia. No se detectaría un comando fallido en medio de la secuencia canalizada. los -o pipefail La opción debe venir en la lista de opciones.

La secuencia para agregar a la parte superior de su secuencia de comandos es:

set -Eeuo pipefail

Aquí hay un script corto llamado "unset-var.sh", con una variable unset en él.

#!/bin/bash

set -Eeou pipefail

echo "$unset_variable"

echo "Do we see this line?"

Cuando ejecutamos el script, unset_variable se reconoce como una variable no inicializada y el script finaliza.

./unset-var.sh

Usar el comando set en un script para terminar el script si ocurre un error

El segundo echo el comando nunca se ejecuta.

Usar trap con errores

El comando Bash trap le permite designar un comando o una función que debe llamarse cuando se genera una señal en particular. Por lo general, esto se usa para captar señales como SIGINT que se eleva cuando presiona la combinación de teclas Ctrl + C. Este script es "sigint.sh".

#!/bin/bash

trap "echo -e 'nTerminated by Ctrl+c'; exit" SIGINT

counter=0

while true
do 
  echo "Loop number:" $((++counter))
  sleep 1
done

los trap El comando contiene un echo comando y el exit dominio. Se activará cuando SIGINT es elevado. El resto del script es un bucle simple. Si ejecuta el script y presiona Ctrl + C, verá el mensaje del trap definición, y el script terminará.

./sigint.sh

Usar trap en un script para atrapar Ctrl + c

Nosotros podemos usar trap con el ERR señal para detectar errores a medida que ocurren. Estos pueden luego ser alimentados a un comando o función. Esto es "trap.sh". Estamos enviando notificaciones de error a una función llamada error_handler.

#!/bin/bash

trap 'error_handler $? $LINENO' ERR

error_handler() {
  echo "Error: ($1) occurred on $2"
}

main() {
  echo "Inside main() function"
  bad_command
  second
  third
  exit $?
}

second() {
  echo "After call to main()"
  echo "Inside second() function"
}

third() {
  echo "Inside third() function"
}

main

La mayor parte del script está dentro del main función, que llama a la second y third funciones Cuando se encuentra un error, en este caso, porque bad_command no existe - el trap declaración dirige el error a la error_handler función. Pasa el estado de salida del comando fallido y el número de línea al error_handler función.

./trap.sh

Uso de trap con ERR para detectar errores en un script

Nuestro error_handler La función simplemente enumera los detalles del error en la ventana del terminal. Si quisieras, podrías agregar un exit comando a la función para que el script finalice. O podría usar una serie de if/elif/fi declaraciones para realizar diferentes acciones para diferentes errores.

Podría ser posible remediar algunos errores, otros podrían requerir que la secuencia de comandos se detuviera.

Un consejo final

Detectar errores a menudo significa adelantarse a las cosas que pueden salir mal y poner un código para manejar esas eventualidades en caso de que surjan. Eso es además de asegurarse de que el flujo de ejecución y la lógica interna de su secuencia de comandos sean correctos.

Si usa este comando para ejecutar su secuencia de comandos, Bash le mostrará una salida de seguimiento a medida que se ejecuta la secuencia de comandos:

bash -x your-script.sh

Bash escribe el resultado de la traza en la ventana del terminal. Muestra cada comando con sus argumentos, si tiene alguno. Esto sucede después de que se hayan expandido los comandos, pero antes de que se ejecuten.

Puede ser de gran ayuda para rastrear errores esquivos.

RELACIONADO: Cómo validar la sintaxis de un script Bash de Linux antes de ejecutarlo

Descubre más contenido

Subir Change privacy settings