Esta es una vieja pregunta, pero ninguna de las respuestas aquí discute el uso de set -e
aka set -o errexit
en los scripts de manejo de paquetes de Debian. El uso de esta opción es obligatorio. en estos scripts, según la política de Debian; la intención aparentemente es evitar cualquier posibilidad de una condición de error no controlada.
Lo que esto significa en la práctica es que debe comprender en qué condiciones los comandos que ejecuta podrían devolver un error y manejar cada uno de esos errores explícitamente.
Los errores comunes son, por ejemplo, diff
(devuelve un error cuando hay una diferencia) y grep
(devuelve un error cuando no hay coincidencia). Puede evitar los errores con el manejo explícito:
diff this that ||
echo "$0: there was a difference" >&2
grep cat food ||
echo "$0: no cat in the food" >&2
(Observe también cómo nos encargamos de incluir el nombre del script actual en el mensaje y de escribir mensajes de diagnóstico en un error estándar en lugar de en la salida estándar).
Si no es realmente necesario o útil un manejo explícito, explícitamente no haga nada:
diff this that || true
grep cat food || :
(El uso de la cáscara :
comando no-op es un poco oscuro, pero se ve con bastante frecuencia).
Solo para reiterar,
something || other
es taquigrafía para
if something; then
: nothing
else
other
fi
es decir, explícitamente decimos que other
debe ejecutarse si y solo si something
falla. La escritura manual if
(y otras declaraciones de control de flujo de shell como while
, until
) también es una forma válida de manejar un error (de hecho, si no fuera así, los scripts de shell conset -e
nunca podrían contener declaraciones de control de flujo!)
Y también, solo para ser explícito, en ausencia de un controlador como este, set -e
causaría que todo el script falle inmediatamente con un error si diff
encuentra una diferencia o si grep
no encuentra una coincidencia.
Por otro lado, algunos comandos no producen un estado de salida de error cuando desea que lo hagan. Los comandos comúnmente problemáticos son find
(el estado de salida no refleja si realmente se encontraron archivos) y sed
(el estado de salida no revelará si el script recibió alguna entrada o si realizó algún comando con éxito). Una protección simple en algunos escenarios es canalizar a un comando que grita si no hay salida:
find things | grep .
sed -e 's/o/me/' stuff | grep ^
Cabe señalar que el estado de salida de una tubería es el estado de salida del último comando en esa tubería. Entonces, los comandos anteriores enmascaran completamente el estado de find
y sed
, y solo le dicen si grep
finalmente tuvo éxito.
(Bash, por supuesto, sí set -o pipefail
; pero los scripts de paquetes de Debian no pueden usar las funciones de Bash. La política dicta firmemente el uso de POSIX sh
para estos scripts, aunque esto no siempre fue así).
En muchas situaciones, esto es algo a tener en cuenta por separado cuando se codifica a la defensiva. A veces tiene que, por ejemplo, pasar por un archivo temporal para poder ver si el comando que produjo esa salida finalizó con éxito, incluso cuando la expresión idiomática y la conveniencia de otro modo le indicarían que usara una tubería de shell.