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

10

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

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 (он будет завершен), и я не был уверен, что это было сделано из-за ошибки, из-за неправильного понимания или из-за чего-то еще.

Кусалананда
источник
eval falseгенерирует ненулевой статус, поэтому я ожидаю, set -eчто сценарий будет прерван на этом этапе. В случае ! set -eне применяется, как !заявление явно проверяет состояние выхода.
fcbsd
@fcbsd Будете ли вы ожидать eval falseзавершения сценария, даже если он является частью списка AND-OR или условного оператора? Я бы не стал.
Кусалананда
Я не уверен, set -eустановлено ли это, если это правильное поведение ... Я согласен, что имеет смысл не заканчиваться условным утверждением.
fcbsd
сыграв еще немного, с sh на CentOS 7 - я бы сказал, что при использовании OpenBSD ksh / sh предназначено поведение, set -eпоэтому `()` - это ответ.
fcbsd

Ответы:

4

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

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

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

continue 3

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

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

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

Исаак
источник
Это повторяет ответ, который я получил из списка рассылки OpenBSD, но с большим количеством слов, спасибо! Я разберу правильный отчет об ошибке, и если ничего не произойдет, я сам посмотрю на исходный код.
Кусалананда
4

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

Я посмотрел на исходный код, и мои выводы:

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

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

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

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и т.д.

mosvy
источник