¿Alguien puede explicar el comportamiento bash / set -e en el fragmento de código a continuación?
#!/bin/bash
# Comment if you want to test the trap only
set -e -o pipefail -u -E
# Comment if you want to test the set -e only
trap "echo ERROR CAUGHT; exit 12" ERR
function reproduce() {
# Trigger arithmetic error on purpose
a=$((1109962735 - hello=12272 + 1))
}
reproduce
# The script is expected to trigger the trap and/or activate the set -e. In both cases it should stop and exit here on error.
status_code=$?
echo "STATUS ${status_code}"
if [[ "${status_code}" != "0" ]];then
echo "FIXME: why was status code not caught by set -e ?"
echo "Executing false to prove set -e is still active"
false
# If the following is not executed then it proves -e is still active
echo "set -e not active !!!!!"
exit 2
fi
Esto es lo que se obtiene al ejecutarlo:
$ bash reproduce.sh
reproduce.sh: line 8: 1109962735 - hello=12272 + 1: attempted assignment to non-variable (error token is "=12272 + 1")
STATUS 1
FIXME: why was status code it not caught by set -e ?
Executing false to prove set -e is still active
ERROR CAUGHT
Comprobando el código de salida
$ echo $?
1
Versión bash
bash --version
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
Reproducido también con
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)
Notas adicionales, relacionadas con comentarios (gracias a todas las sugerencias de todos modos):
- La trampa de comentarios no cambia el comportamiento extraño observado
- Eliminar set -e para mantener la trampa solo activa la trampa.
set -e
contrap
.trap
se invoca en caso de error y se invoca "echo ERROR CAUGHT". Tengo la impresión de quetrap
tiene mayor prioridad queset -e
. También de acuerdo con las preguntas frecuentes de Bash, creo que noset -e
se recomienda , consulte mywiki.wooledge.org/BashFAQ/105 .trap
mecanismo en su lugar, por ejemplotrap "exit 2" ERR
. También para mí, su script imprime "STATUS 0" solamente. Parece que la trampa ERR no es heredada por las funciones de shell, ¿esto ayudaset -o errtrace
? De lo contrario, vea mi enlace anterior sobre por qué debe evitarset -e
en primer lugar.Respuestas:
Simplifiquemoslo; La cantidad mínima de código requerida para reproducir el problema con el que está lidiando es
Según el estándar, esto nunca debería imprimirse
survived
, dice que un shell POSIX que se ejecuta de forma no interactiva saldrá inmediatamente ante un error de expansión . Pero aparentemente Bash no lo cree así. Aunque esta diferencia no está documentada explícitamente en la página del manual, en la descripción del modo POSIX dicePodemos decir que esto significa que en su modo de funcionamiento predeterminado, una sesión Bash no interactiva no se cierra con dicho error, pero como se dio cuenta, tampoco activa el mecanismo errexit ni la trampa ERR. En cambio, asigna un valor distinto de cero a los
$?
movimientos.Para superar esto y obtener el comportamiento esperado, debe definir
reproduce
lo siguienteDe esta forma, el error de expansión tendrá lugar en una subshell y hará que salga con un estado distinto de cero, por lo tanto, errexit y trap podrán capturarlo.
A pedido de dash-o, aquí hay una versión que establece
a
el entorno de ejecución actual cuando la expresión es válidafuente
En la superficie, parece que bash no activará la trampa en varios errores SYNTAX. Solo cuando se ejecuta un comando (externo, incorporado) (y devuelve un valor distinto de cero), la trampa ERR se activará.
Desde la página del manual:
La trampa ERR solo se aplica a PIPELINE . Si bash identifica un error de sintaxis, aborta antes de ejecutar la canalización, por lo tanto, NO hay trampa. Aunque la documentación para '-e' especifica la misma condición (
if a pipeline ... exit with non-zero status
), el comportamiento observado es diferente.Si intenta otras expansiones, por ejemplo, el comando expansion-trap se activa, ya que hay una ejecución de canalización:
Si se usa, pruebe varios errores de sintaxis en la expansión aritmética, la trampa no se activa, no hubo canalización.
Además, otro error de sintaxis de bash no activa la trampa:
()
,[[ ]]
.No pude encontrar una solución que no requiera grandes cambios en el script de origen. ¿Se puede presentar una solicitud de error / función con el equipo de bash?
fuente
( a=$((1109962735 - hello=12272 + 1)) )
o( reproduce )
ejecuta la trampa.a
no se establecerá.