Comportamiento de "eval" bajo "set -e" en expresión condicional

9

Considera los comandos

eval false || echo ok
echo also ok

Normalmente, esperaríamos que esto ejecute la falseutilidad y, dado que el estado de salida es distinto de cero, luego ejecutar echo oky echo also ok.

En todo el POSIX como conchas que utilizo ( ksh93, zsh, bash, dash, OpenBSD ksh, y yash), esto es lo que sucede, pero las cosas se ponen interesantes si permitimos set -e.

Si set -eestá vigente, OpenBSD shy kshshells (ambos derivados de pdksh) terminarán el script al ejecutar el eval. Ningún otro caparazón hace eso.

POSIX dice que un error en una utilidad incorporada especial (como eval) debería hacer que el shell no interactivo finalice. No estoy completamente seguro de si la ejecución falseconstituye "un error" (si lo fuera, sería independiente de set -eestar activo).

La forma de evitar esto parece ser poner evalun sub shell,

( eval false ) || echo ok
echo also ok

La pregunta es si se espera que tenga que hacer eso en un script de shell POSIX-ly correcto, o si es un error en el shell de OpenBSD. Además, ¿qué se entiende por "error" en el texto POSIX vinculado anteriormente?


Información adicional: los shells de OpenBSD ejecutarán echo okambos con y sin set -e el comando

eval ! true || echo ok

Mi código original parecía

set -e
if eval "$string"; then
    echo ok
else
    echo not ok
fi

lo que no la salida not okcon string=falseel uso de las conchas de OpenBSD (sería terminar), y no estaba seguro de que era por diseño, por error o por mala interpretación, o alguna otra cosa.

Kusalananda
fuente
eval falsegenera un estado distinto de cero, por lo que esperaría set -eterminar el script en ese punto. En el caso de ! set -eno se aplica, ya que la !declaración verifica explícitamente el estado de salida.
fcbsd
@fcbsd ¿Esperaría eval falseterminar el script incluso si es parte de una lista AND-OR o una declaración condicional? Yo no lo haría
Kusalananda
No estoy seguro de si set -ese establece si ese es el comportamiento correcto ... Estoy de acuerdo en que tiene sentido no terminar en una declaración condicional.
fcbsd
Después de haber jugado un poco más, con sh en CentOS 7, diría que ese es el comportamiento previsto para ksh / sh de OpenBSD cuando se usa, set -epor lo que `()` es la respuesta.
fcbsd

Respuestas:

4

Que ningún otro shell necesite tal solución alternativa es una fuerte indicación de que es un error en OpenBSD ksh. De hecho, ksh93 no muestra ese problema.

Que haya un ||en la línea de comando debe evitar la salida del shell causada por un código de retorno de 1 en el lado izquierdo.

El error de una función incorporada especial provocará la salida de un shell no interactivo según POSIX, pero eso no siempre es cierto. Intentar continuesalir de un bucle es un error, y continueestá integrado. Pero la mayoría de los proyectiles no salen:

continue 3

Una construcción que emite un error claro pero no sale.

Entonces, la salida activada falsese genera por la set -econdición, no por la característica incorporada del comando ( evalen este caso).

Las condiciones exactas en las que set -edebe salir son bastante más difusas en POSIX.

Isaac
fuente
Esto hace eco de la respuesta que obtuve de la lista de correo de OpenBSD, pero con más palabras, ¡gracias! Ordenaré un informe de error adecuado y, si no sucede nada, miraré el código fuente yo mismo.
Kusalananda
4

[perdón si esta no es una respuesta real, la actualizaré cuando llegue el momento]

Eché un vistazo al código fuente y mis conclusiones son:

1) Es un error / limitación, nada filosófico detrás de esto.

2) La "solución" de la bifurcación portátil de ksh ( mksh) de OpenBSD es muy pobre, solo empeora las cosas, sin realmente arreglarlo:

Nuevo error, diferente de todos los otros shells:

mksh -ec 'eval "false; echo yup"'
yup

bash -ec 'eval "false; echo yup"'
(nothing)

Todavía no está realmente solucionado:

mksh -ec 'eval "set -e; false" || echo yup'
(nothing)

bash -ec 'eval "set -e; false" || echo yup'
yup

Puede reemplazar bashanterior con dash, zsh, yash, ksh93, etc.

Mosvy
fuente