Рассмотрим команды
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
, и т.д.