Как именно `if $ cmd; затем $ cmd; fi` отличаются от `$ cmd && $ cmd`?

В ответе на другой очень хороший вопрос я сделал следующее утверждение:

Согласно моему чтению спецификаций POSIX, использование одного или другого не имеет никакого значения от точки синтаксического анализа.

POSIX указывает, что &&|| списки представляют собой составные команды, что означает, что весь список должен быть прочитан и проанализирован перед выполнением составных простых команд. POSIX также указывает, что команда не должна быть расширена, если она следует за ||OR и другой командой с статусом 0-выхода. Когда вы считаете, что команда, следующая за &&|| зарезервированное слово может легко быть другим сгруппированным { command || ( command ; list) ; } { command || ( command ; list) ; } { command || ( command ; list) ; } делает каждую ветвь &&|| или перечислить его собственную составную команду .

Но POSIX также указывает, что каждая ветвь if...;then...;else...fi construct будет своей собственной составной командой таким образом:

 if compound-list then compound-list [elif compound-list then compound-list] ... [else compound-list] fi 

if составной список должен быть выполнен; если его статус exit равен нулю, then составной список должен быть выполнен, и команда должна завершиться …

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

Так что в принципе, then ' ' не работает по той же причине:

 function() sh: line 2: syntax error: unexpected end of file 

… нет – это не имеет никакого смысла.

Я знаю это…

 [ -e doesntexist ] && $((i=1)) ; echo $i 

… приведет к короткому замыканию любых побочных эффектов и приведет только к \n ewline в результате спецификации, которую я заметил в своем ответе. Результат…

 if [ -e doesntexist ] then $((i=1)) fi echo $i 

… тождественно.

Но я честно использую, if...fi так редко, что я не уверен, что я что-то неправильно понял, и когда я получил комментарий, указывающий на то, что моя интерпретация была неправильной, и если у меня возникнут дополнительные вопросы по этому вопросу, мне нужно только спросить, я удалил ответ вместо этого вопроса: как я ошибался – как они отличаются?

2 Solutions collect form web for “Как именно `if $ cmd; затем $ cmd; fi` отличаются от `$ cmd && $ cmd`?”

Только простые случаи могут быть выражены с помощью && и || , Конструкция if более общая. if CONDITION; then FOO; fi if CONDITION; then FOO; fi эквивалентно CONDITION && FOO (при условии правильного использования фигурных скобок для разграничения блока, если это необходимо), но как только есть else (или elif ), это уже невозможно вообще.

 if CONDITION; then FOO; else BAR; fi 

не эквивалентно

 CONDITION && FOO || BAR 

Если CONDITION истинно, обе конструкции выполняют FOO . Если FOO является ложным, то конструкция if пропускает BAR , тогда как && … || Конструкция выполняет BAR .

И нет, вы не можете обойти это с CONDITION && { FOO; true; } || BAR CONDITION && { FOO; true; } || BAR CONDITION && { FOO; true; } || BAR . Это приводит к тому, что составная команда возвращает true, если CONDITION истинно, а FOO – false, тогда как if CONDITION; then FOO; else BAR; fi if CONDITION; then FOO; else BAR; fi if CONDITION; then FOO; else BAR; fi возвращает false в этом случае.

Это для семантической разницы. Кроме того, есть читаемость: вложенные использования && и || очень быстро становится трудно расшифровать. Я не рекомендую использовать оба в одной команде, фактически, особенно учитывая, что оба оператора имеют одинаковый приоритет в оболочке, тогда как у них есть разные приоритеты в C и большинстве других языков, поддерживающих C (включая Perl и Ruby).

if testlist; then else ...fi if testlist; then else ...fi и testlist && thenlist || elselist testlist && thenlist || elselist вообще не эквивалентны. Разница в том, что в конструкции elselist выполняется только один из thenlist и elselist . В другом случае это зависит от кода выхода thenlist (и возможных блоков eliflist ).

Таким образом, вы должны добавить (например) true в конце выбранного списка результатов, чтобы список имел тот же код выхода, что и тестовый список, вызвавший его выполнение.

 if true; then echo true test -e doesntexist else echo false fi 

можно переписать с помощью && и || убедившись, что код выхода блоков кода. Вместо

 true && { echo true; test -e doesntexist; } || echo false 

тебе нужно

 true && { echo true; test -e doesntexist; true; } || echo false 

Элиф

 if test -e exists; then echo true elif test -e doesntexist echo elif else echo false fi 

было бы

 test -e exists && { echo true; true; } || { test -e doesntexist && { echo elif; true; } || echo false; } 
  • В чем разница между «расширением» и «замещением» в терминах терминологии оболочки?
  • Как сохранить вывод сообщения об ошибке psql в переменной bash?
  • Попытка отправить несколько текстовых вложений через почтовое сообщение
  • Строка, сравниваемая с подстановочными знаками
  • Дискриминация между суб-оболочками CHLD в функции ловушки
  • найти и заменить значения двойной скобки
  • Как ls без рекурсивного
  • Передача переменной в скрипт bash, который использует «EOF» и рассматривает переменную буква
  • Bash - ожидаемое целочисленное выражение
  • Сценарий слияния слов
  • Как создать последовательно пронумерованные имена файлов в bash?
  • динамическое отображение текущего процесса?
  • Linux и Unix - лучшая ОС в мире.