Скрипт Bash с `set -e` не останавливается по команде`… &&… `

13

Я использую, set -eчтобы остановить скрипт bash при первой ошибке .

Все работает хорошо, если я не использую команду с &&:

$ cat script
set -e
cd not_existing_dir && echo 123
echo "I'm running! =P"
$
$ ./script
./script: line 2: cd: not_existing_dir: No such file or directory
I'm running! =P
$

по сравнению с:

$ cat script
set -e
cd not_existing_dir
echo "I'm running! =P"
$
$ ./script
./script: line 2: cd: not_existing_dir: No such file or directory
$

Первый пример все еще повторяет I'm running!, но второй нет. Почему они ведут себя по-разному?

UPD. Аналогичный вопрос: /programming/6930295/set-e-and-short-tests

девятьсот седьмой
источник
Что вы ожидаете, что произойдет в первом примере?
Flup
@Flup Я ожидаю, что сценарий остановится после неудачной cdкоманды
907th
1
Смотрите BashFAQ # 105 для общего обсуждения мест, где set -eповедение удивительно.
Чарльз Даффи
связанные: stackoverflow.com/questions/25794905/…
Сиро Сантилли 新疆 改造 中心 法轮功 六四 事件

Ответы:

9

Это документированное поведение. Страница руководства bash (1) гласит set -e:

Оболочка не завершает работу, если сбойная команда является частью списка команд, следующих сразу за ключевым словом whileили until, частью теста после зарезервированных слов ifили elif, частью любой команды, выполняемой в списке &&или,|| за исключением команды, следующей за последним &&или|| любым команда в конвейере, но последняя, ​​или если возвращаемое значение команды инвертируется !.
[Акцент добавлен.]

И POSIX Shell Command Language Specification подтверждает , что это правильное поведение:

-eУстановка должна игнорироваться при выполнении соединения списка после while, until, ifили elifзарезервированного слова, трубопровод , начиная с !зарезервированным словом, или любая команда из И-ИЛИ списке, кроме последней.

и Раздел 2.9.3 Списки этого документа определяют

Список AND-OR - это последовательность одного или нескольких конвейеров, разделенных операторами " &&" и " ||".

G-Man говорит: «Восстанови Монику»
источник
9

set -eОпция не имеет эффект в некоторых ситуациях, и это стандартное поведение и переносят на совместимой оболочке POSIX.


Ошибка команды является частью конвейера:

false | true; echo printed

будет печатать printed.

И только отказ самого трубопровода считается:

true | false; echo 'not printed'

ничего не напечатает.


Неудачная команда запуска в списке соединения после while, until, if, elifзарезервированное слово, трубопровод , начиная с !зарезервированным словом, или какой - либо команды в составе &&или ||списка , за исключением последнего:

false || true; echo printed

Последняя команда терпит неудачу, все еще set -eвлияет на:

true && false; echo 'not printed'

Не работает подоболочка в составной команде:

(false; echo 'not printed') | cat -; echo printed
cuonglm
источник
Спасибо! Было бы понятнее использовать echo "printed"и echo "not_printed"в ваших примерах (а не echo 1).
907
3
Обратите внимание, что set -eвызывает выход в (false && true); echo not here, но не в { false && true; }; echo here, хотя YMMV с различными оболочками и даже разными версиями одной оболочки. Я не стал бы касаться set -eстолба баржи и вместо этого делал бы правильную обработку ошибок.
Стефан Шазелас
1

я предполагаю, что если-то состояние в целом оценивается как истинное.

Я старался

set -e
if cd not_existing_dir
then  echo 123
fi
echo "I'm running! =P"

кто дает

-bash: cd: not_existing_dir: No such file or directory
I'm running! =P

Код ошибки перехватывается условием if, поэтому bash не будет запускать конец выполнения.

Archemar
источник
Но я не пользуюсьif ... fi
907th
Я знаю, это неявное, если.
Архемар