我如何在Bash中知道一个变量是否已经设置?
例如,我如何检查用户是否提供了函数的第一个参数?
function a {
# if $1 is set ?
}
我如何在Bash中知道一个变量是否已经设置?
例如,我如何检查用户是否提供了函数的第一个参数?
function a {
# if $1 is set ?
}
使用[[ -z "$var" ]]
是判断变量是否设置的最简单方法,但该选项-z
无法区分未设置的变量和已设置为空字符串的变量:
$ set=''
$ [[ -z "$set" ]] && echo "Set" || echo "Unset"
Unset
$ [[ -z "$unset" ]] && echo "Set" || echo "Unset"
Unset
根据变量类型来检查最佳,包括环境变量、参数或正常变量。
对于环境变量:
[[ $(env | grep "varname=" | wc -l) -eq 1 ]] && echo "Set" || echo "Unset"
对于一个参数(例如,检查参数$5
是否存在):
[[ $# -ge 5 ]] && echo "Set" || echo "Unset"
对于一个普通变量(使用辅助函数以优雅的方式完成):
function declare_var {
declare -p "$1" &> /dev/null
}
declare_var "var_name" && echo "Set" || echo "Unset"
注:
$#
: 返回位置参数的数量。declare -p
: 返回传递为参数的变量的定义。如果存在,返回0;如果不存在,则返回1并打印错误消息。&> /dev/null
: 抑制declare -p
的输出,而不影响其返回代码。
您可以做以下事情:
function a {
if [ ! -z "$1" ]; then
echo '$1 is set'
fi
}
-n
而不是取反 -z
。 - Dennis Williamson$1
周围加上引号,即 [ ! -z "$1" ]
。或者在 bash/ksh/zsh 中写成 [[ ! -z $1 ]]
。 - Gilles 'SO- stop being evil'$1
被设置为空字符串,这将会失败。 - HelloGoodbye当Bash选项set -u
启用时,上面的答案无效。此外,它们不是动态的,例如,如何测试名为"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中,如何测试变量是否在"-u"模式下定义
eval "[ ! -z \${$1:-} ]"
更改为间接评估:[ ! -z ${!1:-} ];
。 - user2350426我更喜欢的方法是:
$ var=10
$ if ! ${var+false};then echo "is set";else echo "NOT set";fi
is set
$ unset -v var
$ if ! ${var+false};then echo "is set";else echo "NOT set";fi
NOT set
false
的否定”(会变成true
= “被设置了”)。true
的否定”(因为空结果会被评估为true
),所以最终会变成false
= “未设置”。-z
运算符,该运算符在字符串长度为零时为True。MY_VAR
,则可以使用简单的一行代码来设置它,否则可以选择显示消息。[[ -z "$MY_VAR" ]] && MY_VAR="default"
[[ -z "$MY_VAR" ]] && MY_VAR="default" || echo "Variable already set."
这是我每天都在使用的:
#
# Check if a variable is set
# param1 name of the variable
#
function is_set() { [[ $(eval echo "\${${1}+x}") ]]; }
这在Linux和Solaris下运行良好,适用于Bash 3.0及以下版本。
$ myvar="TEST"
$ is_set myvar ; echo $?
0
$ myvar=
$ is_set myvar ; echo $?
0
$ unset myvar
$ is_set myvar ; echo $?
1
[[ ${!1+x} ]]
来替换长而复杂(包括eval)的test -n "$(eval "echo "\${${1}+x}"")"
。 - user2350426[[
并使其符合 POSIX 标准? - midniteisset() { [ -n "$1" ] && [ -n "$(eval printf '%s' "\${$1+x}" || true)" ]; }
需要注意的是,我们应该将变量名称(不带$)作为文本进行检查。 - midnite[[ $foo ]]
或者
(( ${#foo} ))
或者
let ${#foo}
或者
declare -p foo
我喜欢使用辅助函数来隐藏 Bash 的粗糙细节。在这种情况下,这样做甚至会增加更多(隐藏的)粗糙程度:
# The first ! negates the result (can't use -n to achieve this)
# the second ! expands the content of varname (can't do ${$varname})
function IsDeclared_Tricky
{
local varname="$1"
! [ -z ${!varname+x} ]
}
因为我在这个实现中首先遇到了一些错误(受到Jens的答案和Lionel的启发),所以我想出了一个不同的解决方案:
# Ask for the properties of the variable - fails if not declared
function IsDeclared()
{
declare -p $1 &>/dev/null
}
我发现这种方式更加直接、更具有冲击力,而且更容易理解和记忆。测试用例表明它是等效的:
function main()
{
declare -i xyz
local foo
local bar=
local baz=''
IsDeclared_Tricky xyz; echo "IsDeclared_Tricky xyz: $?"
IsDeclared_Tricky foo; echo "IsDeclared_Tricky foo: $?"
IsDeclared_Tricky bar; echo "IsDeclared_Tricky bar: $?"
IsDeclared_Tricky baz; echo "IsDeclared_Tricky baz: $?"
IsDeclared xyz; echo "IsDeclared xyz: $?"
IsDeclared foo; echo "IsDeclared foo: $?"
IsDeclared bar; echo "IsDeclared bar: $?"
IsDeclared baz; echo "IsDeclared baz: $?"
}
main
local var
不会声明变量(除非后面跟着'=')。有一段时间我以为是这样声明变量的,现在才发现我只是表达了我的意图...我猜这是一个无操作。
IsDeclared_Tricky xyz: 1 IsDeclared_Tricky foo: 1 IsDeclared_Tricky bar: 0 IsDeclared_Tricky baz: 0 IsDeclared xyz: 1 IsDeclared foo: 1 IsDeclared bar: 0 IsDeclared baz: 0
额外奖励:用例
我主要使用这个测试来以一种相当“优雅”和安全的方式给函数提供(和返回)参数(几乎类似于接口...):
# Auxiliary functions
function die()
{
echo "Error: $1"; exit 1
}
function assertVariableDeclared()
{
IsDeclared "$1" || die "variable not declared: $1"
}
function expectVariables()
{
while (( $# > 0 )); do
assertVariableDeclared $1; shift
done
}
# Actual example
function exampleFunction()
{
expectVariables inputStr outputStr
outputStr="$inputStr, World!"
}
function bonus()
{
local inputStr='Hello'
local outputStr= # Remove this to trigger the error
exampleFunction
echo $outputStr
}
bonus
否则:Hello,World!
错误:未声明变量:outputStr。
if [[ ${!xx[@]} ]] ; then echo xx is defined; fi
浏览了所有答案后,这个也可以:
if [[ -z $SOME_VAR ]]; then read -p "Enter a value for SOME_VAR: " SOME_VAR; fi
echo "SOME_VAR=$SOME_VAR"
如果你不使用$SOME_VAR
代替SOME_VAR
,它会将其设置为空值;这里必须使用$
才能生效。
set -u
,它会打印出未定义变量
错误,这时代码将无法运行。 - Michael Heuberger