Запутанное использование && и || операторы

94

Я скользя через /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

Они , кажется, с использованием &&и ||операторов , чтобы получить ответы , основанные на тестах, но я не был в состоянии выкопать documenation относительно этого конкретного использования этих операторов. Кто-нибудь может объяснить, что они делают в этом конкретном контексте?

мистифицировать-Cain
источник

Ответы:

141

Правая сторона &&будет оцениваться только в том случае, если статус выхода левой стороны равен нулю (т. Е. Истина). ||наоборот: он будет оценивать правую сторону только в том случае, если состояние выхода левой стороны отличное от нуля (т. е. ложно).

Вы можете считать [ ... ]программу с возвращаемым значением. Если тест внутри оценивается как true, он возвращает ноль; в противном случае он возвращает ненулевое значение.

Примеры:

$ 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
Вместо «если левая сторона возвращает ноль», я написал бы «если статус выхода команды левой стороны равен нулю». Я нахожу «возврат» немного двусмысленным, так как выход и состояние выхода могут рассматриваться как «возвращаемые значения»
Гленн Джекман
Вы можете не только « считают [ ... ] , что программа», во многих случаях это является . Обычно это в файле /bin/[или /usr/bin/[.
LS
5
Программисты на C сочтут это супер запутанным. Там 0 означает ложь ... В то время как в шеллописании 0 означает истину ... Разум взорван.
Кальмарий
Еще один, который вы могли бы упомянуть, это testвместо ifили [. А if [и , if testкажется, с вкраплениями [и testбез видимой причины или рифмы. testиногда появляется, как на config.site для библиотек поставщиков на Fedora x86_64 .
60

Вот мой шпаргалка:

  • «A; B» Запустите A, а затем B, независимо от успеха A
  • «A && B» Выполнить B, если A успешно
  • «A || B» Запустить B, если A не удалось
  • «A &» Run A в фоновом режиме.
user177073
источник
Здесь есть несколько интересных параллелей лямбда-исчисления, продемонстрированных в работающем JavaScript (определите переменные по порядку); "влево (ака правда)": (a => b => a). "правильно (иначе ложно)" (a => b => 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 left аналогично 0 / пустая строка, right аналогично все остальное.
Дмитрий
28

чтобы расширить ответ @ Shawn-j-Goff сверху, &&это логическое И и ||логическое ИЛИ.

Посмотрите эту часть Расширенного Руководства по написанию сценариев Bash. Некоторые из содержания по ссылке для справки пользователя, как показано ниже.

&& А ТАКЖЕ

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.
Тим Кеннеди
источник
12

По своему опыту я использую && и || сократить оператор 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"

При выполнении нескольких итераций для установки переменных или создания файлов и т. Д. Жизнь становится проще, и сценарий выглядит более гладким, если использовать функцию if в одной строке. Единственным недостатком является то, что становится несколько труднее реализовать несколько команд из одной итерации, однако Вы можете использовать функции.

syme89
источник
Это здорово. Напоминает мне код objc (a == b)? Val = 1: val = 2;
GeneCode
Как я могу использовать эту команду, когда я хочу запустить процесс в фоновом режиме с "&"? Я получаю синтаксическую ошибку для./someScript.sh & && echo 'ok' || echo 'ko'
Katie
4

Есть понятие «короткая стрижка».

Когда (expr1 && expr2)оценивается - оценивается, expr2только если exp1оценивается как «истина». Это потому, что оба expr1И expr2должны быть правдой, (expr1 && expr2)чтобы быть правдой. Если expr1значение expr2равно «false», оно НЕ оценивается (сокращенный вариант), потому что (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

Аналогично для ||(или) - но короткая резка меняется на противоположную.

Larry
источник
5
Логика обычно называется «короткое замыкание». Я никогда не видел фразу «короткий путь». Я упоминаю это, чтобы помочь с поиском ссылок.
LS
-1

Примеры в ответе Шона Дж. Гоффа верны, но объяснение наоборот. Пожалуйста, проверьте:

Правая сторона && будет оцениваться только в том случае, если статус выхода левой стороны - NONZERO. || наоборот: он будет оценивать правую сторону только в том случае, если статус выхода левой стороны равен нулю.

Try2Help
источник
3
Вам известно, что для оболочек нулевой код выхода оценивается как истина, и, следовательно, ненулевой код выхода с левой стороны &&приводит ко всему выражению, возвращающему ложь ?
контррежим
1
Кто-то не одобрил ваши изменения, потому что это был не ваш ответ. Если вы считаете, что какой-то ответ неверен, вы должны понизить его и, возможно, оставить комментарий; если вы считаете, что это требует изменений, вы должны оставить комментарий. Редактирование предназначено для исправления грамматических, форматирующих и орфографических ошибок, которые не меняют смысла ответа.
Techraf 29.09.16
1
@countermode Извините, вы правы, я думал, что в Linux ноль = ложь и ненулевое = истина (как в C и многих других языках / средах / платформах). Я прошу прощения за недоразумение.
Try2Help