cartitas.com

Analizando el modo estricto de bash

4 de enero de 2023

El famoso modo estricto de bash puede ayudarte a escribir scripts o guiones más seguros. Aunque en guiones más grandes tendrás que escribir código para manejar errores de manera correcta, el modo estricto puede ayudarte a detectar errores simples en guiones pequeños.

#!/bin/bash
set -euo pipefail

Vamos a explorar qué significan estas opciones. Verificado con GNU bash, versión 5.1.16.

Opción errexit

La opción set -e detiene la ejecución de tu guión si algún comando regresa un código de salida distinto a 0.

Sin esta opción se ejecutaría el echo.

#!/bin/bash
set -e

ls /no/existe
echo "¡¡¡no debería llegar aquí!!!"
$ ./guión.sh
ls: no se puede acceder a '/no/existe': No existe el fichero o el directorio

Si por alguna razón quieres ignorar el error de un comando, lo puedes ignorar con || true.

#!/bin/bash
set -e

ls /no/importa/que/no/existe || true
echo "ahora sí llega aquí"
$ ./guión.sh
ls: no se puede acceder a '/no/importa/que/no/existe': No existe el fichero o el directorio
ahora sí llega aquí

Para que set -e detecte errores al asignar variables, se recomienda declarar variables así.

a="$(cmd)"

b="$(cmd)"
export b

local c
c="$(cmd)"

d="$(cmd)"
readonly d

Opción nounset

La opción set -u detiene la ejecución de tu guión si alguna variable se usa sin primero antes declararla.

Sin esta opción se ejecutarían los dos comandos de echo. La variable ${num} estaría vacía.

#!/bin/bash
set -u

echo "mi número favorito es ${num}"
echo "¡¡¡no debería llegar aquí!!!"
$ ./guión.sh
./guión.sh: línea 4: num: variable sin asignar

Todo bien, pero existe una sorpresa si quieres usar esta opción y pasar argumentos a tu guión.

Si no pasas un argumento y intentas usar $1, entonces set -u detendrá la ejecución. Para evitar esto, tienes que asignar $1 a una variable con un valor por defecto.

#!/bin/bash
set -u

# Asignar $1 a num. Si $1 no existe, entonces asignar "" a num.
num=${1:-}

if [[ -z "${num}" ]]; then
	echo "uso: $0 <número>"
	exit 1
fi

echo "mi número favorito es ${num}"
$ ./guión.sh
uso: ./guión.sh <número>
$ ./guión.sh 42
mi número favorito es 42

Opción pipefail

La opción set -o pipefail hace que la tuberías regresen el código de salida del primer comando que falle.

Sin esta opción el código de salida sería 0.

#!/bin/bash
set -o pipefail

ls /no/existe | sort
echo "código de salida: $?"
$ ./guión.sh
ls: no se puede acceder a '/no/existe': No existe el fichero o el directorio
código de salida: 2

Véase también