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

Другое решение sed :

$ sed -E 's/^([^.]+).*\](.*)/\1\2/' ip.txt 
2016-10-24 10:25:48 Found 2735 files (298.6 MB) needing backup
2016-10-24 10:25:48 6.08 GB required (including padding), 1.2 TB available
2016-10-24 10:27:56 Copied 3128 items (283.1 MB) from volume Macintosh HD. Linked 5756.
2016-10-24 10:27:59 Created new backup: 2016-10-24-102758
2016-10-24 10:27:59 Failed to send message because the port couldn't be created.
2016-10-24 10:28:00 Could not back up OS X Recovery to /Volumes/BackupA/Backups.backupdb: Error Domain=NSCocoaErrorDomain Code=-69830 "Failed to get info for unmounted Recovery partition (error -69830): This operation requires an unmounted disk" UserInfo={NSLocalizedDescription=Failed to get info for unmounted Recovery partition (error -69830): This operation requires an unmounted disk}
  • ^ ([^.] +) захватывает все не . символов от начала строки
  • . * \] игнорировать все до последнего ] в строке
  • (. *) захватить оставшиеся символы
  • \ 1 \ 2 первая и вторая захваченные группы
  • Примечание. Некоторые версии sed используют -r вместо -E для расширенного параметра регулярного выражения {{ 1}}
    • sed 's / ^ \ ([^.] \ + \). * \] \ (. * \) / \ 1 \ 2 /' , если опция расширенного регулярного выражения недоступен
27
24.03.2019, 22:14
4 ответа

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

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

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

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

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

29
27.01.2020, 19:39

Оператор && выполняет следующую команду, если предыдущая команда имела успешное выполнение (возвращенный код выхода ($?) 0 = логическая истина).

В форме A && B || C , команда (или условие) A оценивается, и если A возвращает истину (успех, код выхода 0), то команда B выполняется. Если A завершился неудачно (таким образом, будет возвращено false - код выхода отличный от 0) и / или B завершится неудачно (возврат false ), то будет выполнена команда C .

Также оператор && используется как AND в проверках условий, а оператор || работает как OR при проверках условий.

В зависимости от того, что вы хотите сделать со своим скриптом, сформируйте A && B || C может использоваться для проверки условий, как в вашем примере, или может использоваться для объединения команд и обеспечения выполнения серии команд, если предыдущие команды имели успешный код выхода 0 .
Вот почему часто встречаются такие команды, как:
do_something && do_something_else_that_depended_on_something .

Примеры:
apt-get update && apt-get upgrade Если обновление не удается, обновление не выполняется (имеет смысл в реальном мире ...).

mkdir test && echo "Something"> test / file
Часть echo "Something" будет выполняться, только если mkdir test завершился успешно и операция вернула код выхода 0 .

./ configure --prefix = / usr && make && sudo make install
Обычно встречается при компиляции заданий для объединения необходимых зависимых команд в цепочку.

Если вы попытаетесь реализовать вышеуказанные «цепочки» с помощью if - , затем - else , вам понадобится гораздо больше команд и проверок (и, следовательно, больше кода для напишите - еще что-то пошло не так) для простой задачи.

Также имейте в виду, что связанные команды с && и || читаются оболочкой слева направо. Вам может потребоваться сгруппировать команды и проверки условий в скобках, чтобы следующий шаг зависел от успешного вывода некоторых предыдущих команд. Например, см. Это:

root@debian:$ true || true && false;echo $?
1 
#read from left to right
#true OR true=true AND false = false = exit code 1=not success

root@debian:$ true || (true && false);echo $?
0 
# true OR (true AND false)=true OR false = true = exit code 0 = success

Или пример из реальной жизни:

root@debian:$ a=1;b=1;c=1;[[ $a -eq 1 ]] || [[ $b -eq 1 ]] && [[ $c -eq 2 ]];echo $?
1 
#condition $a = true OR condition b = true AND condition $c = false
#=> yields false as read from left to right, thus exit code=1 = not ok

root@debian:$ a=1;b=1;c=1;[[ $a -eq 1 ]] || [[ $b -eq 1 && $c -eq 2 ]];echo $?
0 
#vars b and c are checked in a group which returns false, 
#condition check of var a returns true, thus true OR false yields true = exit code 0

Имейте в виду, что некоторые команды возвращают разные коды выхода в зависимости от выполняемого процесса или возвращают разные коды в зависимости от своих действий (например, команда GNU diff , возвращает 1 , если два файла различаются, и 0 в противном случае). С такими командами следует обращаться осторожно в && и || .

Также, чтобы собрать всю головоломку вместе, обратите внимание на конкатенацию команд с использованием оператора ; . В формате A; B; C все команды будут выполняться последовательно независимо от кода выхода команды A и B .

7
27.01.2020, 19:39

Большинству людей легче понять форму if ... then ... else ... fi .

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

 $ 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

&& и || являются операторами короткого замыкания , как только становится известен результат, дальнейшие ненужные тесты пропускаются. a && b || c сгруппирован как (a && b) || c . Сначала выполняется a . Если он терпит неудачу , что определяется как не возвращающее статус выхода 0, то группа (a && b) известна как неудачно и b запускать не нужно. || не знает результат выражения, поэтому необходимо выполнить c . Если a завершается успешно (возвращает ноль), тогда оператор && еще не знает результат a && b , поэтому должен выполнить b ] выяснить. Если b завершается успешно, то a && b завершается успешно, и || знает, что общий результат успешен, поэтому не нужно запускать c ]. Если b терпит неудачу, то || по-прежнему не знает значение выражения, поэтому необходимо запустить c .

30
27.01.2020, 19:39

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

Некоторые примеры могут лучше всего проиллюстрировать это ...

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

cmda  && cmdb  || cmdc

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

cmda; cmdb  && cmdc  || cmdd

Как cmda завершается, игнорируется.
Если cmdb завершается как истина, выполняется cmdc .
Если cmdb завершается false, cmdc НЕ выполняется, а cmdd -.

cmda  && cmdb; cmdc

Если cmda завершается как истина, выполняется cmdb , за которым следует cmdc .
Если cmda завершается как false, cmdb НЕ выполняется , но cmdc выполняется.

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

cmda  && cmdb
cmdc  

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

cmda && {cmdb; cmdc; }
Если cmda завершается как истина, выполняется cmdb , за которым следует cmdc .
Если cmda завершается false, ни 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
}
1
27.01.2020, 19:39

Теги

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