Почему команда после `||` выполняется, даже если предыдущая команда выполнена успешно? - PullRequest
1 голос
/ 13 апреля 2019

Я использую оценку короткого замыкания (с && и ||) в функции bash, и я не понимаю поведение, которое я вижу. Я хочу, чтобы функция вернулась если первое число не больше второго:

[[ 5 > 2 ]] && echo true || echo false && return

#    ^             ^                   ^
# true so       do this        not this && this


[[ 5 > 8 ]] && echo true || echo false && return

#    ^             ^                   ^ 
# false so   don't do this      do this && this

но функция возвращает в любом случае. Почему команда return выполняется независимо от статуса первой команды?

Вместо return Я пытался break, но это не работает из-за отсутствия внутри цикла.

  1. Почему return, кажется, выполняется в обоих этих случаях?

  2. Как еще можно завершить работающую функцию?

Ответы [ 2 ]

4 голосов
/ 13 апреля 2019
    stmt<sub>1</sub>  &&  stmt<sub>2</sub>    ||  stmt<sub>3</sub>    &&  stmt<sub>4</sub>

оценивается как

( ( stmt<sub>1</sub>  &&  stmt<sub>2</sub> )  ||  stmt<sub>3</sub> )  &&  stmt<sub>4</sub>

т.е. слева направо.

Так что логика

Execute stmt<sub>1</sub>
If it succeeds,
then
    execute stmt<sub>2</sub>
endif
If stmt<sub>1</sub> succeeds and stmt<sub>2</sub> succeeds,
then
    <i>(do nothing here)</i>
else                    # i.e., if stmt<sub>1</sub> fails,  OR  stmt<sub>1</sub> succeeds and then stmt<sub>2</sub> fails
    execute stmt<sub>3</sub>
endif
If stmt<sub>1</sub> succeeds and stmt<sub>2</sub> succeeds,
                  OR  stmt<sub>3</sub> succeeds,
then
    execute stmt<sub>4</sub>
endif

С stmt<sub>2</sub> и stmt<sub>3</sub> оба echo утверждения, они оба всегда успешны, и так stmt<sub>4</sub> (оператор return) всегда выполняется.

Я подозреваю, что вы ожидали

( stmt<sub>1</sub>  &&  stmt<sub>2</sub> )  ||  ( stmt<sub>3</sub>  &&  stmt<sub>4</sub> )

и вы можете получить такое поведение (в целом), набрав скобки, просто так:

 ( [[ 5 > <i>N</i> ]] && echo true )  ||  ( echo false && return )         <b># No, don’t do this</b>

или фигурные скобки:

{ [[ 5 > <i>N</i> ]] && echo true; }  ||  { echo false && return; }

Обратите внимание, что вы должны иметь пробел после { и точка с запятой перед }.

Обратите внимание, что в скобках команды выполняются в подоболочках, в то время как с фигурными скобками они не (они работают в контексте основной оболочки). В вашем конкретном примере кода вы должны использовать фигурные скобки (по крайней мере, для части после ||), , поскольку return не имеет никакого эффекта, если он запускается в подоболочке.

2 голосов
/ 13 апреля 2019

Используйте if вместо логических операторов.

if [[ 5 > 8 ]]
then echo true
else
    echo false
    return
fi

См. приоритет логических операторов оболочки для объяснения того, как операторы объединяются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...