В Bash, как я могу проверить, определена ли переменная в режиме "-u"
Я только что обнаружил set -u
в bash, и это помогло мне найти несколько ранее невидимых ошибок. Но у меня также есть сценарий, где мне нужно проверить, определена ли переменная до вычисления значения по умолчанию. Лучшее, что я придумал для этого:
if [ "${variable-undefined}" == undefined ]; then
variable="$(...)"
fi
который работает (пока переменная не имеет строкового значения undefined
). Мне было интересно, есть ли лучший способ?
Ответы
Ответ 1
Что не работает: проверка строк с нулевой длиной
Вы можете протестировать строки undefined несколькими способами. Использование стандартного условного условного выражения выглядит следующим образом:
# Test for zero-length string.
[ -z "$variable" ] || variable='foo'
Это не будет работать с set -u
.
Что работает: условное назначение
В качестве альтернативы вы можете использовать условное присваивание, что более похоже на Bash. Например:
# Assign value if variable is unset or null.
: "${variable:=foo}"
Из-за того, как Bash обрабатывает расширение этого выражения, вы можете безопасно использовать его с set -u
, не получая ошибку "bash: переменная: несвязанная переменная".
Ответ 2
Это то, что я нашел, работает лучше всего для меня, принимая во внимание другие ответы:
if [ -z "${varname-}" ]; then
...
varname=$(...)
fi
Ответ 3
В bash 4.2 и новее существует явный способ проверить, установлена ли переменная, которая должна использовать -v.
Пример из вопроса может быть реализован следующим образом:
if [[ ! -v variable ]]; then
variable="$(...)"
fi
См. http://www.gnu.org/software/bash/manual/bashref.html#Bash-Conditional-Expressions
Если вы хотите только установить переменную, если она еще не установлена, вам, вероятно, лучше что-то делать по этим строкам:
variable="${variable-$(...)}"
Обратите внимание, что это не относится к определенной, но пустой переменной.
Ответ 4
Ответы выше не являются динамическими, например, как проверять переменную с именем "dummy"? Попробуйте следующее:
is_var_defined()
{
if [ $# -ne 1 ]
then
echo "Expected exactly one argument: variable name as string, e.g., 'my_var'"
exit 1
fi
# Tricky. Since Bash option 'set -u' may be enabled, we cannot directly test if a variable
# is defined with this construct: [ ! -z "$var" ]. Instead, we must use default value
# substitution with this construct: [ ! -z "${var:-}" ]. Normally, a default value follows the
# operator ':-', but here we leave it blank for empty (null) string. Finally, we need to
# substitute the text from $1 as 'var'. This is not allowed directly in Bash with this
# construct: [ ! -z "${$1:-}" ]. We need to use indirection with eval operator.
# Example: $1="var"
# Expansion for eval operator: "[ ! -z \${$1:-} ]" -> "[ ! -z \${var:-} ]"
# Code execute: [ ! -z ${var:-} ]
eval "[ ! -z \${$1:-} ]"
return $? # Pedantic.
}
Связано: Как проверить, установлена ли переменная в Bash?
Ответ 5
В начале вашего script вы можете определить свои переменные с пустым значением
variable_undefined=""
Тогда
if [ "${variable_undefined}" == "" ]; then
variable="$(...)"
fi
Ответ 6
Unfortunatly [[ -v variable ]]
не поддерживается в более старых версиях bash (по крайней мере, не в версии 4.1.5. У меня есть Debian Squeeze)
Вместо этого вы можете использовать дополнительную оболочку:
if (true $variable)&>/dev/null; then
variable="$(...)"
fi
Ответ 7
if [ "${var+SET}" = "SET" ] ; then
echo "\$var = ${var}"
fi
Я не знаю, как далеко назад поддерживается ${var + value}, но он работает, как минимум, в 4.1.2. В старых версиях не было ${var + value}, они имели только ${var: + value}. Разница в том, что ${var: + value} будет оцениваться только до "value", если $var устанавливается в непустую строку, а ${var + value} также будет оцениваться как "значение", если $var устанавливается в пустую строку.
Без [[-v var]] или ${var + value} Я думаю, вам придется использовать другой метод. Вероятно, тест подоболочки, описанный в предыдущем ответе:
if ( set -u; echo "$var" ) &> /dev/null; then
echo "\$var = ${var}
fi
Если ваш shell-процесс уже активирован "set -u" , он также будет активен в подоболочке без необходимости "set -u" , но включение его в команду subhell позволяет также работать, если родительский процесс не включил "set -u" .
(Вы также можете использовать другой процесс, такой как "printenv" или "env", чтобы проверить наличие переменной, но тогда он будет работать, только если экспортируется переменная.)