我如何知道是否在Bash中设置了变量?

例如,如何检查用户是否向函数提供了第一个参数?

function a {
    # if $1 is set ?
}

当前回答

我喜欢辅助功能来隐藏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} ]
}

因为我在这个实现中首先遇到了bug(灵感来自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

测试用例还显示,局部var不声明var(除非后面跟着“=”)。很长一段时间以来,我以为我是这样声明变量的,只是为了发现我只是表达了我的意图。。。我想这是不可能的。

IsDeclared_Tricky xyz:1IsDeclared_Tricky foo:1IsDeclared_Tricky条:0我声明的Tricky baz:0IsDeclared xyz:1IsDeclared foo:1IsDeclared栏:0IsDeclared 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

如果调用时声明了所有必需的变量:

你好,世界!

其他:

错误:未声明变量:outputStr

其他回答

对于那些希望在使用set-u的脚本中检查未设置或空的脚本:

if [ -z "${var-}" ]; then
   echo "Must provide var environment variable. Exiting...."
   exit 1
fi

常规[-z“$var”]检查将因var而失败;未绑定变量如果设置-u但[-z“${var-}”]如果var未设置而不失败,则扩展为空字符串。

case "$1" in
 "") echo "blank";;
 *) echo "set"
esac

虽然这里所述的大多数技术都是正确的,但Bash 4.2支持对变量的存在进行实际测试(man-Bash),而不是测试变量的值。

[[ -v foo ]]; echo $?
# 1

foo=bar
[[ -v foo ]]; echo $?
# 0

foo=""
[[ -v foo ]]; echo $?
# 0

值得注意的是,与许多其他方法(如使用[-z)不同,这种方法在set-u/set-o nounset模式下用于检查未设置的变量时不会导致错误。

if [[ ${!xx[@]} ]] ; then echo xx is defined; fi

要检查非空/非零字符串变量,即如果已设置,请使用

if [ -n "$1" ]

它与-z相反。我发现自己使用-n多于-z。

您可以像这样使用它:

if [ -n "$1" ]; then
  echo "You supplied the first parameter!"
else
  echo "First parameter not supplied."
fi