Являются ли другие выражения эквивалентными логическим и & & или || и где я должен отдать предпочтение одному другому?

Я изучаю структуры принятия решений, и я натолкнулся на эти коды:

if [ -f ./myfile ]
then
     cat ./myfile
else
     cat /home/user/myfile
fi


[ -f ./myfile ] &&
cat ./myfile ||
cat /home/user/myfile

Оба они ведут себя одинаково. Существуют ли какие-либо преимущества в использовании одного способа от другого?

25 голосов | спросил Subhaa Chandar 8 Jpm1000000pmSun, 08 Jan 2017 23:04:28 +030017 2017, 23:04:28

3 ответа


23

Нет, конструкции if A; then B; else C; fi и A && B || C не эквивалентны .

С помощью if A; then B; else C; fi, команда A всегда выполняется и выполняется (по крайней мере, попытка выполнить его), а затем либо команду B, либо команду C оцениваются и выполняются.

С помощью A && B || C, то же самое для команд A и B, но отличается для C: command C оценивается и выполняется, если либо A не удается выполнить или B.

В вашем примере предположим, что вы chmod u-r ./myfile, тогда, несмотря на [ -f ./myfile ] преуспеть, вы будете cat /home/user/myfile

Мой совет: используйте A && B или A || B все, что вам нужно, это остается легко читать и понимать, и нет никакой ловушки. Но если вы имеете в виду, если ... тогда ... еще ... затем используйте if A; then B; else C; fi.

ответил xhienne 8 Jpm1000000pmSun, 08 Jan 2017 23:37:04 +030017 2017, 23:37:04
27

Большинство людей считают более понятным if ... then ... else ... fi.

Для a && b || c, вы должны быть уверены, что b возвращает true. Это является причиной тонких ошибок и является хорошей причиной, чтобы избежать этого стиля. Если b не возвращает true, это не одно и то же.

 $ if true; then false ; else echo boom ; fi
 $ true && false || echo boom
 boom

Для очень коротких тестов и действий, которые не имеют предложения else, сокращенная длина является привлекательной, например.

 die(){ printf "%s: %s\n" "$0" "$*" >&2 ; exit 1; }

 [ "$#" -eq 2] || die "Needs 2 arguments, input and output"

 if [ "$#" -ne 2 ] ; then
     die "Needs 2 arguments, input and output"
 fi

&& и || являются ---- +: = 10 =: + ----, как только результат будет известен, дополнительные ненужные тесты будут пропущены. short circuiting operators сгруппирован как a && b || c. Выполняется первый (a && b) || c. Если он a, который определяется как не возвращающий статус выхода 0, тогда группа fails известен как (a && b) и fail не нужно запускать. b не знает результат выражения, поэтому ему нужно выполнить ||. Если c преуспевает (возвращает ноль), то a еще не знает результат &&, поэтому должен запускаться a && b, чтобы узнать. Если b преуспевает, то b преуспевает, а a && b знает, что общий результат - успех, поэтому не нужно запускать ||. Если c терпит неудачу, то b все еще не знать значение выражения, поэтому нужно запустить ||.

ответил icarus 8 Jpm1000000pmSun, 08 Jan 2017 23:35:10 +030017 2017, 23:35:10
2

Большая часть путаницы в этом может быть связана с документацией bash, вызывающей эти AND и OR . Логически аналогично && и || найденные внутри квадратных скобок, они функционируют по-разному.

Некоторые примеры могут показать это наилучшим образом ...

  

ПРИМЕЧАНИЕ. Одинарные и двойные квадратные скобки ([ ... ] и [[ ... ]])   команды сами по себе, которые выполняют сравнение и возвращают выход   код. Им действительно не нужен if.

cmda  && cmdb  || cmdc

Если cmda завершает true, cmdb.
Если cmda завершает ложь, cmdb НЕ выполняется, но cmdc.

cmda; cmdb  && cmdc  || cmdd

Вывод cmda игнорируется.
Если cmdb завершает true, cmdc.
Если cmdb завершает ложь, cmdc НЕ выполняется, а cmdd.

cmda  && cmdb; cmdc

Если cmda завершает true, cmdb, а затем cmdc.
Если cmda завершает ложь, cmdb НЕ выполняется , но cmdc.

А? Почему выполняется cmdc?
Потому что для интерпретатора точка с запятой (;) и новая строка означают то же самое. Bash видит, что строка кода как ...

cmda  && cmdb
cmdc  

Чтобы достичь ожидаемого, мы должны заключить cmdb; cmdc внутри фигурных скобок, чтобы сделать их Compound Command (групповая команда) . Дополнительная конечная точка с запятой является просто требованием синтаксиса { ...; }. Итак, мы получаем ...

cmda && { cmdb; cmdc; }
Если cmda завершает выполнение true, cmdb, а затем cmdc.
Если cmda завершает ложь, ни cmdb или cmdc.
Выполнение продолжается со следующей строкой.

Использование

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

Вот пример из некоторого кода запуска ...

fnInit () {
  :
  _fn="$1"
  ### fnInit "${FUNCNAME}" ...
  ### first argument MUST be name of the calling function
  #
  [[ "$2" == "--help-all" ]]  && { helpAll                      ; return 0; }
  ### pick from list of functions
  #
  [[ "$2" == "--note-all" ]]  && { noteAll                      ; return 0; }
  ### pick from notes in METAFILE
  #
  [[ "$2" == "--version"  ]]  && { versionShow "${_fn}" "${@:3}"; return 0; }
  #
  [[ "$2" == "--function" ]]  && {
    isFnLoaded "$3"           && { "${@:3}"                     ; return 0; }
    #
    errorShow functionnotfound "Unknown function:  $3"
    return 0
  }
  ### call any loaded function
  #
  [[ "$2" == "--help" || "$2" == "-h" ]]  && { noteShow "$_fn" "${@:3}"; return 0; }
  ### fnInit "${FUNCNAME}" --help or -h
  #
  return 1
}
ответил DocSalvager 13 Jam1000000amFri, 13 Jan 2017 05:19:48 +030017 2017, 05:19:48

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132