Есть два случая, когда я нахожу :
полезным:
Переменные по умолчанию
#!/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}
Синтаксис говорит набор 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
Однако я считаю, что есть несколько альтернативных подходов, которые лучше, чем пустой блок:
Поместите условие в функцию:
exotic_condition() { [ -f foo ] && bar || baz; }
if ! exotic_condition; then
do_something_here
fi
Поместите условие в фигурные скобки (или круглые скобки, но скобки порождают процесс подоболочки, и любые изменения, внесенные в среду внутри подоболочки, не будут видны за пределами подоболочки) перед отрицанием:
if ! { [ -f foo ] && bar || baz; } then
do_something_here
fi
Используйте ||
вместо 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"