Какова полезность команды: в сценариях оболочки, учитывая, что она явно ничего не делает?

В ответе на этот вопрос о комментариях в сценариях оболочки указано, что : – это пустая команда, которая явно ничего не делает (но не должна использоваться для комментариев).

Что было бы полезностью команды, которая ничего не делает?

Обычно я использую true в циклах; Я думаю, что это более ясно:

 while true; do ... done 

Одно место, которое я обнаружил, действительно полезно: в случае, если вам нужно что-то сопоставить, но ничего не хотите делать. Например:

 case $answer in ([Yy]*) : ok ;; (*) echo "stop."; exit 1 ;; esac 

Первоначально он использовался для определения того, что это была программа оболочки Bourne, а не C-скомпилированная программа. Это было до shebang и нескольких языков сценариев (csh, perl). Вы все равно можете запустить скрипт, начиная с::

 $ echo : > /tmp/xyzzy $ chmod +x /tmp/xyzzy $ ./xyzzy 

Обычно он запускает скрипт в $SHELL (или /bin/sh ).

С тех пор основное использование – это оценка аргументов. Я все еще использую:

 : ${EDITOR:=vim} 

для установки значения по умолчанию в скрипте.

: полезно для записи циклов, которые должны быть завершены изнутри.

 while : do ...stuff... done 

Это будет работать вечно, если не будет вызван break или exit , или оболочка получит завершающий сигнал.

Если вы хотите, чтобы в сценариях оболочки был задан оператор «если», вы либо используете условие «нет», которое может выглядеть глупо для некоторых тестов, либо вы используете «:» в предложении true, с реальным кодом в false- пункт.

 if [ some-exotic-condition ] then : else # Real code here fi 

«Экзотическое условие» может быть чем-то, что вы не хотите отрицать, или это намного яснее, если вы не используете «отрицательную логику».

Я только использовал это в дополнение к символу # для временного комментирования строки, в ситуации, когда комментирование строки приводит к синтаксической ошибке из-за дефекта в грамматике оболочки, что не позволяет пустую последовательность команд :

 if condition ; then :# temporarily commented out command fi 

Без: у нас есть отсутствующая последовательность команд, которая является синтаксической ошибкой.

Есть два случая, когда я нахожу : полезно:

Назначения переменных по умолчанию

 #!/bin/sh # set VAR to "default value" if not already set in the environment : "${VAR=default value}" # print the value of the VAR variable. Note that POSIX says the behavior # of echo is implementation defined if the first argument is '-n' or if any # argument contains a '\', so use printf instead of echo. printf '%s\n' "VAR=${VAR}" 

Это удобный способ разрешить пользователям сценария оболочки переопределять параметр без редактирования скрипта. (Тем не менее, аргументы командной строки лучше, потому что вы не рискуете неожиданным поведением, если пользователь случайно имеет переменную, которую вы используете в экспортируемой среде.) Вот как пользователь может переопределить параметр:

 VAR="other value" ./script 

Синтаксис ${VAR=value} говорит, чтобы установить value VAR для value если VAR еще не установлен, затем разверните его до значения переменной. Поскольку мы все еще не заботимся о значении переменной, оно передается в качестве аргумента для команды no-op : выбросить ее.

Несмотря на то, что : – команда no-op, расширение выполняется оболочкой (а не командой : !!) Перед запуском команды : так что назначение переменной по-прежнему происходит (если применимо).

Также было бы приемлемо использовать true или какую-либо другую команду вместо : но код становится сложнее читать, потому что намерение менее понятно.

Также будет работать следующий скрипт:

 #!/bin/sh # print the value of the VAR variable. Note that POSIX says the behavior # of echo is implementation defined if the first argument is '-n' or if any # argument contains a '\', so use printf instead of echo. printf '%s\n' "VAR=${VAR=default value}" 

Но вышесказанное гораздо сложнее поддерживать. Если строка, содержащая ${VAR} , добавляется выше этой строки printf , необходимо переместить расширение назначения по умолчанию. Если разработчик забывает переместить это задание, появляется ошибка.

Что-то положить в пустой условный блок

Пустые условные блоки, как правило, следует избегать, но иногда они полезны:

 if some_condition; then # todo: implement this block of code; for now do nothing. # the colon below is a no-op to prevent syntax errors : fi 

Некоторые люди утверждают, что наличие пустого блока if может сделать код более легким для чтения, чем отрицание теста. Например:

 if [ -f foo ] && bar || baz; then : else do_something_here fi 

возможно, легче читать, чем:

 if ! [ -f foo ] || ! bar && ! baz; then do_something_here fi 

Однако я считаю, что есть несколько альтернативных подходов, которые лучше, чем пустой истинный блок:

  1. Положите условие в функцию:

     exotic_condition() { [ -f foo ] && bar || baz; } if ! exotic_condition; then do_something_here fi 
  2. Поместите условие в фигурные скобки (или круглые скобки, но в круглых скобках появится процесс подоболочки, и любые изменения, внесенные в среду внутри подоболочки, не будут видны за пределами подоболочки), прежде чем отрицать:

     if ! { [ -f foo ] && bar || baz; } then do_something_here fi 
  3. Использовать || вместо того, if :

     [ -f foo ] && bar || baz || { do_something_here } 

    Я предпочитаю этот подход, когда реакция представляет собой простой однострочный слой, такой как условия утверждения:

     log() { printf '%s\n' "$*"; } error() { log "ERROR: $*" >&2; } fatal() { error "$@"; exit 1; } [ -f foo ] && bar || baz || fatal "condition not met" 

В старой оболочке pre-bourne в древних версиях UNIX команда : первоначально была предназначена для указания меток для goto (это была отдельная команда, которая наматывает вход туда, где метка найдена, поэтому метки не могут быть отдельным синтаксисом что оболочка знает об этом. if была также отдельной командой.) Вскоре она стала использоваться для комментариев, прежде чем появился синтаксис комментария ( # был использован для backspace), и в эти дни для совместимости есть что угодно.

В дополнение к использованию в качестве инструкции, которая ничего не делает, вы можете использовать ее для комментирования одиночных утверждений, превратив их в аргументы для:.