Я недавно столкнулся с некоторыми сценариями, как это:
( set -e ; do-stuff; do-more-stuff; ) || echo failed
Это выглядит хорошо для меня, но это не работает! set -e
Не применяется, когда вы добавляете ||
. Без этого все работает нормально:
$ ( set -e; false; echo passed; ); echo $?
1
Однако, если я добавлю ||
, то set -e
игнорируется:
$ ( set -e; false; echo passed; ) || echo failed
passed
Использование реальной отдельной оболочки работает как положено:
$ sh -c 'set -e; false; echo passed;' || echo failed
failed
Я пробовал это в нескольких различных оболочках (bash, dash, ksh93) и все ведут себя одинаково, так что это не ошибка. Может кто-нибудь объяснить это?
shell
shell-script
Сумасшедший ученый
источник
источник
||
внешняя подоболочка влияет на поведение внутри подоболочки.(set -e; echo 1; false; echo 2)
с(set -e; echo 1; false; echo 2) || echo 3
Ответы:
Согласно этой теме , это поведение POSIX определяет для использования "
set -e
" в подоболочке.(Я тоже был удивлен.)
Во-первых, поведение:
Второй пост отмечает,
Еще немного в четвертом посте, также от Эрика Блейка,
Такое поведение определенно удивительно. Это противоречит интуиции: можно ожидать, что возобновление работы даст
set -e
эффект, и что окружающий контекст не будет иметь прецедента; кроме того, формулировка стандарта POSIX не делает это особенно ясным. Если вы читаете его в контексте, где команда не выполняется, правило не применяется: оно применяется только в окружающем контексте, однако оно применяется к нему полностью.источник
set -e; (false; echo passed;) || echo failed
. На самом деле меня не удивляет, что в данном случае -e игнорируется, учитывая формулировку стандарта. В моем случае, однако, я явно устанавливаю -e в подоболочке и ожидаю, что подоболочка завершится неудачно. В подоболочке нет списка «И-ИЛИ» ...if
и||
и&&
заразны? это абсурдДействительно, не
set -e
имеет никакого эффекта внутри подоболочек, если вы используете||
оператор после них; например, это не сработает:Аарон Д. Мараско в своем ответе отлично объясняет, почему он так себя ведет.
Вот небольшой трюк, который можно использовать для исправления: запустите внутреннюю команду в фоновом режиме, а затем сразу дождитесь ее.
wait
Встроенный возвращают код завершения внутренней команды, и теперь вы используете||
после тогоwait
, а не внутренней функции, поэтомуset -e
работает должным образом внутри последний:Вот общая функция, которая основывается на этой идее. Он должен работать во всех POSIX-совместимых оболочках, если вы удаляете
local
ключевые слова, т.е. заменяете всеlocal x=y
простоx=y
:Пример использования:
Выполнение примера:
Единственное, что вам нужно знать при использовании этого метода, это то, что все изменения переменных оболочки, сделанные из команды, которую вы передаете
run
, не будут распространяться на вызывающую функцию, потому что команда выполняется в подоболочке.источник
Я не исключаю, что это ошибка только потому, что так ведут себя несколько оболочек. ;-)
У меня есть больше удовольствия, чтобы предложить:
Могу я привести цитату из man bash (4.2.24):
Возможно, вычисление нескольких команд приводит к игнорированию || контекст.
источник
eval
Трюк не работает для меня. Я пробовал bash, bash в режиме posix и dash.set -e
.set -e
сломан по дизайну. Я бы не использовал его ни для чего, кроме простейших сценариев оболочки без структур управления, подоболочек или подстановок команд.Обходной путь, когда usint toplevel
set -e
Я пришел к этому вопросу, потому что я использовал
set -e
в качестве метода обнаружения ошибок:и без
||
этого сценарий перестанет работать и никогда не достигнетdo_more_stuff
.Поскольку, похоже, не существует чистого решения, я думаю, что я просто буду делать простые
set +e
сценарии:источник