¿Cuándo no funciona hered_errexit?

¿Cuándo no funciona hered_errexit?
#!/usr/bin/env bash
set -e
shopt -s inherit_errexit
a=$(cat no-such-file)
echo survived
$ /tmp/a.sh
cat: no-such-file: No such file or directory
#!/usr/bin/env bash
set -e
shopt -s inherit_errexit
echo -n $(cat no-such-file)
echo survived
$ /tmp/a.sh
cat: no-such-file: No such file or directory
survived
#!/usr/bin/env bash
set -e
shopt -s inherit_errexit
f() { :; }
f $(cat no-such-file)
echo survived
$ /tmp/a.sh
cat: no-such-file: No such file or directory
survived

¿Algún otro caso? ¿O alguna generalización?

Respuesta1

TL, DR: para beneficiarse set -e, asigne directamente el resultado de una sustitución de comando a una variable (opcionalmente con cadenas adicionales alrededor). No combine varias sustituciones de comandos ni utilice una sustitución de comandos en un argumento de comando.

El problema no es con inherit_errexit. Esta funcionando. El problema son las limitaciones de set -e(que no son específicas de bash: otros shells tipo sh tienen el mismo problema).

Demostración: ejecute esta variante de su segundo ejemplo.

$ cat b2.sh 
#!/usr/bin/env bash
set -e
shopt -s inherit_errexit
echo -n $(cat no-such-file; echo >&2 after cat)
echo survived
$ ./b2.sh 
cat: no-such-file: No such file or directory
survived

Tenga en cuenta que echo >&2 after catno se ejecutó. Lo sería si inherit_errexitestuviera apagado.

El problema es que set -esólo detiene la ejecución por error en casos simples. Si la sustitución de un comando devuelve un estado de error, eso no detiene la ejecución del comando simple que contiene la sustitución. Como máximo, podría establecer el estado de retorno del comando simple, lo que a su vez podría detener la ejecución del script. Un "comando simple" consta de asignaciones, redirecciones y un nombre y argumentos de comando ejecutable opcionales. Si falla una redirección, el estado de retorno es 1. De lo contrario, si hay un nombre de comando, el estado de retorno del comando simple es el estado de retorno del comando ejecutable. De lo contrario, el estado de devolución es el estado de devolución de la última sustitución de comando, o 0 si no hay ninguna. Aquí hay algunos ejemplos de comandos simples:

  • true </no/such/file→ estado 1 debido a la redirección fallida
  • false </dev/null→ estado 1 defalse
  • a=b→ estado 0 por no tener ninguna pieza que pueda fallar
  • a=$(exit 0) b=$(exit 1) c=$(exit 2)→ estado 2 desde la última sustitución de comando
  • a=$(exit 2) b=$(exit 1) c=$(exit 0)→ estado 0 desde la última sustitución de comando
  • true $(exit 0) $(exit 1) $(exit 2)→ estado 0 detrue

Una vez más, en todos los casos, set -esólo detendrá el script si el estado del comando es distinto de cero. El estado de los comandos integrados no es directamente relevante.

Y así, en su segundo script echo -n $(…)tiene el estado 0, desde echo(excepto si echono se puede escribir), independientemente de lo que suceda dentro de la sustitución del comando. Por lo tanto, el script no se detendrá aquí incluso si set -eestá activo. Asimismo, en el tercer script, f $(…)tiene el estado 0 de f.

información relacionada