Неправильне використання && та || операторів


92

Я скупився через /etc/rc.d/init.d/sendmailфайл (я знаю, що це майже ніколи не використовується, але я навчаюсь на іспит), і я трохи заплутався щодо операторів &&і ||операторів. Я читав, де вони можуть бути використані в таких висловлюваннях, як:

if [ test1 ] && [ test2 ]; then
     echo "both tests are true"
elif [ test1 ] || [ test2 ]; then
     echo "one test is true"
fi

Однак цей скрипт показує однорядкові заяви, такі як:

[ -z "$SMQUEUE" ] && SMQUEUE="QUEUE"
[ -f /usr/sbin/sendmail ] || exit 0

Здається, вони використовують операторів &&і ||для отримання відповідей на основі тестів, але мені не вдалося розкопати документацію щодо саме цього використання цих операторів. Чи може хтось пояснити, що вони роблять у цьому конкретному контексті?

Відповіді:


140

Права частина &&буде оцінена лише у тому випадку, якщо стан виходу лівої сторони дорівнює нулю (тобто вірно). ||- навпаки: правий бік буде оцінено лише в тому випадку, якщо статус виходу лівої сторони не дорівнює нулю (тобто хибний).

Ви можете вважати [ ... ]програму зі зворотним значенням. Якщо тест всередині оцінюється як істинний, він повертає нуль; в іншому випадку воно повертається ненульово

Приклади:

$ false && echo howdy!

$ true && echo howdy!
howdy!
$ true || echo howdy!

$ false || echo howdy!
howdy!

Додаткові примітки:

Якщо ви це зробите which [, ви можете побачити, що [насправді вказує на програму! Зазвичай це насправді не той, який працює в сценаріях; біжи, type [щоб побачити, що насправді запускається. Якщо ви тьмяний спробувати використовувати програму, просто дати повний шлях приблизно так: /bin/[ 1 = 1.


6
Коли ви бачите "X або Y", ви перевіряєте X. Якщо це правда, ви вже знаєте відповідь на "X або Y" (це правда), тому не потрібно тестувати Y. Якщо це правда, ви не знаєте відповідь на "X чи Y", тому вам потрібно перевірити Y. Коли ви бачите "X і Y", ви перевіряєте X. Якщо це неправда, ви вже знаєте відповідь на "X і Y" (це неправда), так немає потреби перевіряти Y. Якщо X відповідає дійсності, то вам потрібно перевірити Y, щоб перевірити, чи "X і Y" вірно.
Девід Шварц

2
Замість "якщо ліва сторона повертає нуль", я б написав "якщо стан виходу команди лівої сторони дорівнює нулю". Я вважаю "повернення" трохи неоднозначним, оскільки вихід і статус виходу можна вважати "значеннями повернення"
glenn jackman

Ви не тільки можете " вважати [ ... ] програмою", в багатьох випадках це є . Це зазвичай у файлі /bin/[або /usr/bin/[.
LS

5
Програмісти на C вважають це супер заплутаним. Там 0 означає неправду ... У той час як в оболонках 0 означає істину ... Розум вибухнув.
Кальмарій

Ще один, який ви могли б згадати, testзамість ifабо [. А if [та , if testздається, з вкрапленнями [і testбез видимої причини або рими. testз’являється при нагоді, як-от на config.site для lib постачальників у Fedora x86_64 .

58

Ось мій шпаргалка:

  • "A; B" Виконати A, а потім B, незалежно від успіху A
  • "A&B" Виконати B, якщо A вдалося
  • "A || B" Виконати B, якщо A не вдалося
  • "А &" Виконати A у фоновому режимі.

Тут є кілька цікавих паралелей обчислення лямбда, продемонстрованих у робочому JavaScript (визначте змінні в порядку); "Вліво (ака правда)": (a => b => a). "Право (ака брехня)": (a => b => b). "A; B" "тоді" (a => b => (() => b())(a())). "A&B", якщо без іншого (коли) " (a => b => a()(() => right)(b)). "A || B" "інше без if (якщо)" (a => b => a()(b)(() => right)). "a && b || c" "ifThenElse" (a => b => c => (unless(when(a)(b))(c))()).
Дмитро

1
зауважте, що в bash, лівий - аналог 0 / порожній рядок, правий аналог - це все інше.
Дмитро

27

щоб розширити відповідь @ Shawn-j-Goff згори, &&це логічне І, і ||це логічне АБО.

Дивіться цю частину Розширеного посібника з написання сценарію. Частина вмісту із посилання для ознайомлення з користувачем, як показано нижче.

&& І

if [ $condition1 ] && [ $condition2 ]
#  Same as:  if [ $condition1 -a $condition2 ]
#  Returns true if both condition1 and condition2 hold true...

if [[ $condition1 && $condition2 ]]    # Also works.
#  Note that && operator not permitted inside brackets
#+ of [ ... ] construct.

|| АБО

if [ $condition1 ] || [ $condition2 ]
# Same as:  if [ $condition1 -o $condition2 ]
# Returns true if either condition1 or condition2 holds true...

if [[ $condition1 || $condition2 ]]    # Also works.
#  Note that || operator not permitted inside brackets
#+ of a [ ... ] construct.

10

Зі свого досвіду я використовую && та || щоб зменшити оператор if до одного рядка.

Скажімо, ми шукаємо файл під назвою /root/Sample.txt, тоді традиційна ітерація в оболонці буде такою:

if [ -f /root/Sample.txt ]
then
    echo "file found"
else
    echo "file not found"
fi

Ці 6 рядків можна зменшити до одного рядка:

[[ -f /root/Sample.txt ]] && echo "file found" || echo "file not found"

Під час виконання декількох ітерацій для встановлення змінних або створення файлів тощо, життя простіше, і сценарій виглядає стрункішим, використовуючи єдиний рядок, якщо функція, єдиний недолік полягає в тому, що реалізувати кілька команд з однієї ітерації стає трохи складніше ви можете використовувати функції.


Це круто. Нагадує мені код objc (a == b)? Val = 1: val = 2;
GeneCode

Як я можу використовувати цю команду, коли хочу запустити процес у фоновому режимі з "&"? Я отримую синтаксичну помилку./someScript.sh & && echo 'ok' || echo 'ko'
Katie

3

Існує поняття «коротке різання».

Коли (expr1 && expr2)оцінюється - expr2оцінюється лише в тому випадку, якщо exp1оцінюється як "правда". Це тому, що обидва expr1І expr2повинні бути вірними, (expr1 && expr2)щоб бути правдою. Якщо expr1значення "false" expr2НЕ оцінюється (скорочення), оскільки (expr1 && expr2)воно вже "flase".

Спробуйте наступне - припустимо, що файл F1існує, а файл F2не існує:

( [ -s F1 ] && echo "File Exists" )  # will print "File Exists" - no short cut
( [ -s F2 ] && echo "File Exists" )  # will NOT print "File Exists" - short cut

Аналогічно для ||(або) - але коротка обрізка обернена назад.


4
Зазвичай логіку називають "коротким замиканням". Я ніколи не бачив вжитої фрази "скорочення". Я згадую це, щоб допомогти у пошуку посилань.
LS

-1

Приклади у відповіді Шона Дж. Гоффа є правильними, але пояснення навпаки. Будь ласка, перевірте:

Права частина && буде оцінена лише у тому випадку, якщо ліва сторона виходу NONZERO. || є протилежним: він буде оцінювати правий бік лише у тому випадку, якщо статус лівого виходу є лівим.


3
Вам відомо, що для оболонок нульовий код виходу оцінюється як істинний і, таким чином, ненульовий код виходу з лівої сторони &&призводить до того, що весь вираз повертає помилкове ?
контрмодес

1
Хтось не схвалив ваші зміни, тому що це не ваша відповідь. Якщо ви вважаєте, що якась відповідь є невірною, вам слід спростувати її та, можливо, залишити коментар; якщо ви вважаєте, що це вимагає змін, залиште коментар. Редагування призначене для виправлення граматики, форматування та написання помилок, які не змінюють значення відповіді.
techraf

1
@countermode Вибачте, ви праві, я подумав, що в Linux нульовий = false та ненульовий = true (як у C та багатьох інших мовах / середовищах / платформах). Прошу вибачення за непорозуміння.
Try2Help
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.