为什么 [[ -z ]] 和 [[ -v ]] 有不同的语法?

Phi*_*ide 8 bash test variable

如果我想在未设置变量的情况下执行某些命令,我​​正在使用:

if [[ -z "$a" || -z "$v" ]]
then
  echo "a or b are not set"
fi
Run Code Online (Sandbox Code Playgroud)

然而相同的语法不适用于-v,我必须使用:

if [[ -v a && -v b ]]
then
  echo "a & b are set"
fi
Run Code Online (Sandbox Code Playgroud)

这背后的历史是什么?我不明白为什么语法不一样。我读过这-v是 bash (4.2) 的一个新成员

dha*_*hag 21

测试运营商-v-z只是不一样。

运算符-z判断字符串是否为空。因此,确实可以[[ -z "$a" ]]很好地近似“变量a未设置”,但不是完美的:

  • 如果a设置为空字符串而不是未设置,则表达式将产生真;

  • 如果a未设置并且nounset启用了该选项, 则封闭脚本将失败。

另一方面,即使在边缘情况下,-v a也将完全“a设置变量”。应该明确的是,传递$a,而不是a-v是不对的,因为测试操作员看到它之前,它会展开可能,未设置变量; 因此,检查该变量(由其名称指向)并判断它是否已设置必须成为该操作员任务的一部分。

  • 请注意,`[[ -v ]]` 也存在边缘情况。就像变量 _array_ 类型一样,只有在设置了 `${var[0]}`(实际上与 `$var` 相同)时,`[[ -v var ]]` 才返回 true。对于关联数组,`${var[0]}` 也是(例如不是 `${var[00]}`)。如果数组设置了任何值,`[[ -v var[@] ]]` 将返回 true(对于设置为 `var=()` 的变量将返回 false)。这归结为在 ksh/bash 中完成变量输入的疯狂方式。请参阅 `zsh` 以了解更容易混淆的变量类型。 (4认同)
  • 更简洁地说:`-z` 测试一个值,而 `-a` 测试一个 *name*。 (2认同)
  • @chepner,您的意思是 -v 测试名称吗? (2认同)

cho*_*oba 7

-z和的含义有所不同-v

echo Empty:
x=""  # Same with x=
[[ -z $x ]] && echo z
[[ -v  x ]] && echo v
unset x

echo Unset
[[ -z $x ]] && echo z
[[ -v  x ]] && echo v
Run Code Online (Sandbox Code Playgroud)

通过使用-z,您无法区分分配了空值的变量和未分配任何值的变量。

此外,[[ -z $x ]]对于 仍然是明智的set -u,而[[ -v x ]]不是。