Оператори &&
та ||
оператори не є точними замінниками вбудованих даних для if-то-else Хоча якщо їх застосовувати обережно, вони можуть зробити те саме.
Єдиний тест простий і однозначний ...
[[ A == A ]] && echo TRUE # TRUE
[[ A == B ]] && echo TRUE #
[[ A == A ]] || echo FALSE #
[[ A == B ]] || echo FALSE # FALSE
Однак спроба додати кілька тестів може дати неочікувані результати ...
[[ A == A ]] && echo TRUE || echo FALSE # TRUE (as expected)
[[ A == B ]] && echo TRUE || echo FALSE # FALSE (as expected)
[[ A == A ]] || echo FALSE && echo TRUE # TRUE (as expected)
[[ A == B ]] || echo FALSE && echo TRUE # FALSE TRUE (huh?)
Чому і ЛЖЕ, і ІСТИНА перегукуються?
Тут відбувається те, що ми не усвідомили цього &&
і ||
перевантажені операторами, які діють інакше в умовних тестових дужках, [[ ]]
ніж у списку І та АБО (умовне виконання), який ми маємо тут.
З баш-сторінки (відредаговано) ...
Списки
Список - це послідовність одного або декількох трубопроводів, розділених одним з операторів;, &, && або ││ і необов'язково закінчується одним із;, &, або. З цих операторів списку && та ││ мають однаковий пріоритет, за яким слідують; та &, які мають рівний пріоритет.
Послідовність одного або декількох нових рядків може з’являтися в списку замість крапки з комою для розмежування команд.
Якщо команду припиняє оператор управління &, оболонка виконує команду у фоновому режимі в нижній частині. Оболонка не чекає завершення команди, а стан повернення - 0. Команди, розділені а; виконуються послідовно; оболонка чекає, коли кожна команда завершиться по черзі. Статус повернення - це стан виходу останньої виконаної команди.
Списки AND і OR - це послідовності одного з декількох конвеєрів, розділених відповідно операторами управління && та ││. Списки AND і OR виконуються з лівою асоціативністю.
Список AND має вигляд ...
command1 && command2
Command2 виконується, якщо і тільки якщо, command1 повертає статус виходу в нуль.
Список АБО має форму ...
command1 ││ command2
Command2 виконується, якщо і лише тоді, коли command1 повертає ненульовий статус виходу.
Статус повернення списку AND і OR - це стан виходу останньої команди, виконаної у списку.
Повернення до нашого останнього прикладу ...
[[ A == B ]] || echo FALSE && echo TRUE
[[ A == B ]] is false
|| Does NOT mean OR! It means...
'execute next command if last command return code(rc) was false'
echo FALSE The 'echo' command rc is always true
(i.e. it successfully echoed the word "FALSE")
&& Execute next command if last command rc was true
echo TRUE Since the 'echo FALSE' rc was true, then echo "TRUE"
Добре. Якщо це правильно, то чому наступний останній приклад взагалі щось повторює?
[[ A == A ]] || echo FALSE && echo TRUE
[[ A == A ]] is true
|| execute next command if last command rc was false.
echo FALSE Since last rc was true, shouldn't it have stopped before this?
Nope. Instead, it skips the 'echo FALSE', does not even try to
execute it, and continues looking for a `&&` clause.
&& ... which it finds here
echo TRUE ... so, since `[[ A == A ]]` is true, then it echos "TRUE"
Ризик виникнення логічних помилок при використанні декількох &&
або ||
в списку команд досить високий.
Рекомендації
Сингл &&
або ||
в списку команд працює так, як очікувалося, тому досить безпечно. Якщо це ситуація, коли ви не потребуєте іншого пункту, щось більш чітке можна виконати (наприклад, фігурні дужки потрібні для групування двох останніх команд) ...
[[ $1 == --help ]] && { echo "$HELP"; exit; }
Множинні &&
і ||
операторів, де кожна команда , за винятком останнього тест (тобто всередині дужок [[ ]]
), як правило , також безпечні , як і всі , крім останнього оператора поводяться , як очікувалося. Останній оператор діє більше як then
або else
пункт.
&&
і||
оболонки, як і у них,cmd1 && cmd2 || cmd3
мають однаковий пріоритет,&&
в((...))
і[[...]]
має перевагу над||
(((a || b && c))
є((a || (b && c)))
). Те саме стосується-a
/-o
вtest
/[
іfind
та&
/|
вexpr
.