Verhalten von "eval" unter "set -e" im bedingten Ausdruck

9

Betrachten Sie die Befehle

eval false || echo ok
echo also ok

Normalerweise würden wir erwarten , dass dies das auszuführen falseDienstprogramm , und da der Exit - Status ungleich Null ist, dann ausführen echo okund echo also ok.

In allen POSIX-wie Muscheln ich ( ksh93, zsh, bash, dash, OpenBSD ksh, und yash), das ist , was passiert, aber die Dinge interessant , wenn wir ermöglichen set -e.

Wenn dies der set -eFall ist, beenden OpenBSDs shund kshShells (beide abgeleitet von pdksh) das Skript, wenn das ausgeführt wird eval. Keine andere Shell macht das.

Laut POSIX sollte ein Fehler in einem speziellen integrierten Dienstprogramm (z. B. eval) dazu führen, dass die nicht interaktive Shell beendet wird. Ich bin mir nicht ganz sicher, ob das Ausführen false"einen Fehler" darstellt (wenn dies der Fall wäre, wäre es unabhängig davon set -e, aktiv zu sein).

Der Weg, dies zu umgehen, scheint darin zu bestehen, das evalin eine Sub-Shell zu setzen.

( eval false ) || echo ok
echo also ok

Die Frage ist, ob ich das in einem POSIX-korrekten Shell-Skript tun muss oder ob es ein Fehler in der OpenBSD-Shell ist. Was ist mit "Fehler" im oben verlinkten POSIX-Text gemeint?


Zusätzliche Informationen: Die OpenBSD-Shells führen echo oksowohl mit als auch ohne set -e im Befehl aus

eval ! true || echo ok

Mein ursprünglicher Code sah aus wie

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

Dies würde bei Verwendung der OpenBSD-Shells nicht ausgegeben werden (es würde enden), und ich war mir nicht sicher, ob es beabsichtigt, versehentlich oder durch Missverständnisse oder etwas anderes war.not okstring=false

Kusalananda
quelle
eval falsegeneriert einen Status ungleich Null, sodass ich erwarten würde set -e, das Skript an diesem Punkt zu beenden. Im Falle von ! set -egilt nicht, da die !Anweisung den Exit-Status explizit überprüft.
fcbsd
@fcbsd Würden Sie erwarten eval false, das Skript zu beenden, auch wenn es Teil einer UND-ODER-Liste oder einer bedingten Anweisung ist? Ich würde nicht.
Kusalananda
Ich bin nicht sicher, ob festgelegt set -eist, ob dies das richtige Verhalten ist ... Ich stimme zu, dass es sinnvoll ist, nicht in einer bedingten Anweisung zu beenden.
fcbsd
Nachdem ich mit sh unter CentOS 7 noch mehr gespielt habe, würde ich sagen, dass dies das beabsichtigte Verhalten von OpenBSDs ksh / sh ist, wenn es verwendet wird, set -ealso ist das `()` die Antwort.
fcbsd

Antworten:

4

Dass keine andere Shell eine solche Problemumgehung benötigt, ist ein starker Hinweis darauf, dass es sich um einen Fehler in OpenBSD ksh handelt. Tatsächlich zeigt ksh93 ein solches Problem nicht.

Dass sich ||in der Befehlszeile ein befindet, muss den Shell-Exit vermeiden, der durch einen Rückkehrcode von 1 auf der linken Seite verursacht wird.

Der Fehler einer speziellen integrierten Funktion führt zum Beenden einer nicht interaktiven Shell gemäß POSIX. Dies ist jedoch nicht immer der Fall. Der Versuch, continueaus einer Schleife herauszukommen, ist ein Fehler und continueein integrierter Fehler. Aber die meisten Muscheln gehen nicht aus:

continue 3

Ein eingebautes Gerät, das einen eindeutigen Fehler ausgibt, aber nicht beendet wird.

Der Exit on falsewird also durch die set -eBedingung generiert , nicht durch die eingebaute Charakteristik des Befehls ( evalin diesem Fall).

Die genauen Bedingungen, unter denen beendet werden set -esoll, sind in POSIX ziemlich unscharf.

Isaac
quelle
Dies spiegelt die Antwort wider, die ich von der OpenBSD-Mailingliste erhalten habe, aber mit mehr Worten, danke! Ich werde einen richtigen Fehlerbericht aussortieren, und wenn nichts passiert, werde ich mir den Quellcode selbst ansehen.
Kusalananda
4

[Entschuldigung, wenn dies keine echte Antwort ist, werde ich sie aktualisieren, wenn ich dazu komme]

Ich habe mir den Quellcode angesehen und meine Schlussfolgerungen sind:

1) Es ist ein Fehler / eine Einschränkung, nichts Philosophisches dahinter.

2) Das "Update" von der tragbaren Gabel von OpenBSDs ksh ( mksh) ist sehr schlecht, was die Sache nur noch schlimmer macht, ohne es wirklich zu reparieren:

Neuer Fehler, der sich von allen anderen Shells unterscheidet:

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

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

Immer noch nicht wirklich behoben:

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

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

Sie können ersetzen bashoben mit dash, zsh, yash, ksh93etc.

Mosvy
quelle