Как именно `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 так редко, что я не уверен, что я что-то неправильно понял, и когда я получил комментарий, указывающий на то, что моя интерпретация была неправильной, и если у меня возникнут дополнительные вопросы по этому вопросу, мне нужно только спросить, я удалил ответ вместо этого вопроса: как я ошибался – как они отличаются?

  • Как использовать входной файл неточных файлов для операции?
  • Фильтры поиска LDAP с использованием BASH
  • Почему в этом сценарии оболочки bourne выполняется `exec 2> & 1`?
  • Определите, работает ли рабочий каталог Git из сценария
  • Как узнать, печатает ли программа на stderr или stdout в терминале?
  • Как скопировать / объединить два каталога, и если два файла имеют одинаковое имя, переименуйте более старый, добавив время его модификации
  • Что делает эта линия в bash? Параметрируемая || имяскрипт
  • Вывод команды Pipe на Yad, а также запись результата в файл журнала
  • 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; } 
    Linux и Unix - лучшая ОС в мире.