Esta es una vieja pregunta, pero ninguna de las respuestas aquí discute el uso de set -eaka set -o errexiten 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 otherdebe ejecutarse si y solo si somethingfalla. 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 -ecausaría que todo el script falle inmediatamente con un error si diffencuentra una diferencia o si grepno 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 findy sed, y solo le dicen si grepfinalmente 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 shpara 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.