Рассмотрим команды
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
не применяется, как!
заявление явно проверяет состояние выхода.eval false
завершения сценария, даже если он является частью списка AND-OR или условного оператора? Я бы не стал.set -e
установлено ли это, если это правильное поведение ... Я согласен, что имеет смысл не заканчиваться условным утверждением.set -e
поэтому `()` - это ответ.Ответы:
То, что никакая другая оболочка не нуждается в таком обходном пути, является убедительным свидетельством того, что это ошибка в OpenBSD ksh. На самом деле, ksh93 не показывает такой проблемы.
То, что есть
||
в командной строке, должно избегать выхода из оболочки, вызванного кодом возврата 1 с левой стороны от него.Ошибка специальной встроенной функции приведет к выходу неинтерактивной оболочки в соответствии с POSIX, но это не всегда так. Попытка
continue
выхода из цикла является ошибкой иcontinue
является встроенной. Но большинство снарядов не выходят на:Встроенная функция, которая выдает явную ошибку, но не завершает работу.
Таким образом, выход on
false
генерируетсяset -e
условием, а не встроенной характеристикой команды (eval
в данном случае).Точные условия
set -e
выхода должны быть более размытыми в POSIX.источник
[извините, если это не настоящий ответ, я обновлю его, когда доберусь до него]
Я посмотрел на исходный код, и мои выводы:
1) Это ошибка / ограничение, ничего философского за этим нет.
2) «Исправление» для этого из переносной ветки ksh (
mksh
) в OpenBSD очень плохое, только усугубляет ситуацию без реального исправления:Новый баг, отличающийся от всех остальных оболочек:
Все еще не очень исправлено:
Вы можете заменить
bash
вышеdash
,zsh
,yash
,ksh93
и т.д.источник