Сценарий Bash: почему вызывается функция, если оператор работает иначе, чем просто вызов функции сам по себе - PullRequest
0 голосов
/ 19 марта 2020

Давайте сравним эти 2 сценария.

Сценарий 1:

#!/bin/sh

set -e

foo() {
  return 1
}

bar() {
  foo
  echo "this shouldn't be executed"
}

bar

Сценарий 2:

#!/bin/sh

set -e

foo() {
  return 1
}

bar() {
  foo
  echo "this shouldn't be executed"
}

if bar; then
  echo "yes"
else
  echo "no"
fi

Поскольку существует set -e, я ожидаю, что если функция возвращает ненулевое значение, любая вызывающая ее функция также останавливается на этой строке и возвращает то же значение.

Другими словами, в первом скрипте foo возвращает 1, поэтому bar будет также верните 1 и строка echo "this shouldn't be executed" не будет выполнена. В конце сценарий завершится с кодом 1.

Однако во втором сценарии, внезапно, если я вызову bar внутри оператора if, он не остановится на строке, где он вызывает foo. Это будет продолжаться и повторять «это не должно выполняться».

Я не понимаю. Что такого особенного в заявлениях if? Это выглядит так: если условие оператора, set -e не имеет никакого эффекта.

Кстати, подобное неожиданное поведение происходит, если я просто вызываю bar || echo "this should execute". Эхо не произойдет, и вместо этого строка внутри бара выполнит echo "this shouldn't be executed".

Ответы [ 3 ]

2 голосов
/ 19 марта 2020

Исключения для опции -e явно задокументированы (отформатированы для выделения)

-e
Немедленно завершить работу, если конвейер (который может состоять из одной простой команды), list или составная команда (см. ОБРАЗЕЦ ОБОЛОЧКИ выше) завершается с ненулевым статусом.

Оболочка не завершает работу, если команда, которая завершается неудачно, является частью списка команд, который следует сразу же после этого. или до ключевого слова, часть теста после зарезервированных слов if или elif, часть любой команды, выполненной в && или || список, за исключением команды, следующей за последним символом && или ||, любой командой в конвейере, кроме последней, или если возвращаемое значение команды инвертируется с помощью!.

Если составная команда отличается от подоболочки возвращает ненулевое состояние, поскольку команда завершилась неудачно, в то время как -e игнорировалась, оболочка не завершается. Ловушка ERR, если установлена, выполняется до выхода из оболочки. Этот параметр применяется к среде оболочки и каждой среде подоболочки отдельно (см. Выше КОМАНДА ИСПОЛНЕНИЯ ИСПОЛНЕНИЯ) и может привести к выходу подоболочек перед выполнением всех команд в подоболочке.

Это распространяется на вызовы функций; если сбой bar как часть условия if не должен вызывать выход из оболочки, равно как и команда сбой при выполнении bar.

1 голос
/ 19 марта 2020

Части, извлеченные из bash ручной набор встроенных :

-e

[...] Оболочка не завершается, если команда этот сбой является [...] частью теста в операторе if [...]

[...]

Если составная команда или функция оболочки выполняется в контексте, где -e игнорируется, ни одна из команд, выполняемых в составной команде или теле функции, не будет затронута параметром -e, даже если -e установлено и команда возвращает состояние ошибки. [...]

Что особенного в операторах if?

set -e явно игнорируется в командах if .

0 голосов
/ 20 марта 2020

Это, несомненно, подвергнет меня критике за нарушение табу, но лично я предпочитаю использовать тестовые конструкции, а не встроенные циклы if или if для ветвления. Это может обойти такие формы непредсказуемости, как то, что вы испытываете.

if bar; then
   echo "yes"
   else
   echo "no"
fi

Выше приведен основной способ сделать это. Моя последняя, ​​ниже: -

[[ bar ]] && echo "yes"
echo "no"

Эта вторая форма ближе к тому, что вы встретите в сборке с ее «условными скачками», и в результате, на мой взгляд, больше отражает физическую электронику. Сначала выполняется тест, и хотя тогда нет оператора, вторая команда выполняется только в случае неудачи теста.

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

...