Поведение «eval» при «set -e» в условном выражении

Поведение «eval» при «set -e» в условном выражении

Рассмотрим команды

eval false || echo ok
echo also ok

Обычно мы ожидаем, что это запустит falseутилиту и, поскольку статус выхода ненулевой, затем выполнит echo okи echo also ok.

Во всех POSIX-подобных оболочках, которые я использую ( ksh93, zsh, bash, dash, OpenBSD kshи yash), именно это и происходит, но все становится интереснее, если мы включим set -e.

Если set -eдействует, то OpenBSD shи kshоболочки (обе производные от pdksh) завершат скрипт при выполнении eval. Никакая другая оболочка этого не делает.

POSIX говоритчто ошибка в специальной встроенной утилите (такой как eval) должна приводить к завершению неинтерактивной оболочки. Я не совсем уверен, falseявляется ли выполнение "ошибкой" (если бы это было так, то это не зависело бы от set -eактивности).

Похоже, что обойти это можно, поместив evalв под-оболочку,

( eval false ) || echo ok
echo also ok

Вопрос в том, должен ли я сделать это в правильном скрипте оболочки POSIX, или это ошибка в оболочке OpenBSD? Кроме того, что подразумевается под "ошибкой" в тексте POSIX, ссылка на который приведена выше?


Дополнительная информация: оболочки OpenBSD будут выполнять обе команды: echo okс указанием и без указанияset -e

eval ! true || echo ok

Мой исходный код выглядел так

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

которые бынетвывод not okс string=falseиспользованием оболочек OpenBSD (он завершался), и я не был уверен, было ли это намеренным решением, ошибкой или недопониманием, или чем-то еще.

решение1

То, что ни одна другая оболочка не нуждается в таком обходном пути, является весомым указанием на то, что это ошибка в OpenBSD ksh. Фактически, ksh93 не показывает такой проблемы.

Наличие ||в командной строке символа должно исключить выход из оболочки, вызванный кодом возврата 1 в левой части.

Ошибкаособенныйвстроенный вызовет выход из неинтерактивной оболочкисогласно POSIXно это не всегда так. Попытка continueвыйти из цикла является ошибкой и continueвстроена. Но большинство оболочек не выходят при:

continue 3

Встроенная функция, которая выдает явную ошибку, но не завершает работу.

Таким образом, выход falseгенерируется условием set -e, а не встроенной характеристикой команды ( evalв данном случае).

Точные условия, при которых set -eдолжен произойти выход, в POSIX гораздо более размыты.

решение2

[извините, если это не настоящий ответ, я обновлю его, когда доберусь до него]

Я взглянул на исходный код и пришел к следующим выводам:

1) Это ошибка/ограничение, в этом нет ничего философского.

2) «Исправление» этой ошибки из переносимой версии OpenBSD ksh ( mksh) —оченьплохо, только ухудшает ситуацию, на самом деле не исправляя ее:

Новый баг, отличный от всех остальных оболочек:

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

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

Все еще не до конца исправлено:

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

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

Вы можете заменить bashуказанное выше на dash, zsh, yash, ksh93, и т.д.

Связанный контент