重要的是要记住,空的 shell 变量与未设置的 shell 变量不同 - 尽管不能使用 [ test ] 的任何一种形式来区分。 test 所能做的就是报告变量扩展的值 - 决定这一点的是参数扩展。例如:
var=value
echo "${var+I am \$var and I am set. I am currently ${var:+not} empty.}"
###OUTPUT###
I am $var and I am set. I am currently not empty.
再次:
var=
echo "${var+I am \$var and I am set. I am currently ${var:+not} empty.}"
###OUTPUT###
I am $var and I am set. I am currently empty.
[ test ]:
{ _nstr() { echo 'I just evaluated a ""null string!' ; }
[ -z "$var" ] && _nstr
[ -z "" ] && _nstr
unset var
[ -z "$var" ] && _nstr
echo "${var+I am \$var and I am set. I am currently ${var:+not} empty.}"
}
###OUTPUT###
I just evaluated a ""null string!
I just evaluated a ""null string!
I just evaluated a ""null string!
希望这能把它带回家:
var=value
[ -z "${var+}" ] && _nstr
###OUTPUT###
I just evaluated a ""null string!
如果您想以可移植的方式确定变量是否为空,则可以这样做:
${var:+false} [ -n "${var+1}" ] && echo \$var is set and null
我认为您可以很好地利用 shell 的参数扩展来处理此类情况,在某些情况下甚至可以用一块石头杀死两只鸟(参见第一个示例)。这绝对应该是便携式的。以下是来自 open group 的 POSIX shell 指南的不完整复制/粘贴:http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02
${parameter:-word}
- 使用默认值。如果参数为
unset或null,则替换为单词的扩展;否则,参数的值将被替换。
${parameter:=word}
- 分配默认值。如果参数为
unset 或null,则将字的扩展分配给参数。在所有情况下,应替换参数的最终值。这种方式只能分配变量,不能分配位置参数或特殊参数。
${parameter:?[word]}
- 如果为 Null 或未设置,则指示错误。如果参数是
unset 或null,word 的扩展(或者如果 word 被省略,则指示它未设置的消息)应写入标准错误,并且 shell 以非零退出状态退出。否则,应替换参数的值。交互式 shell 无需退出。
${parameter:+word}
- 使用替代值。如果参数为
unset或null,则替换为null;否则,用词的扩展代替。
示例:
${parameter:-word}
- 在此示例中,仅当
x 为 null 或 unset 时才会执行 ls。 ($( ls) 命令替换符号在命令替换中解释。)
${x:-$(ls)}
${parameter:=word}
% unset X
% echo ${X:=abc}
abc
编辑:
我刚刚注意到 Ashish 的单线,因为粘贴它感觉有点便宜,我想做点什么。所以这里有一个 POSIX 参数扩展 set-test one-liner:
_JAIL="" ; echo "_JAIL is ${_JAIL:-unset or null.}"
嗯,我猜还是很便宜。
EDIT2:
所以我刚刚注意到:"...虽然这些适用于我现在编写的脚本,但我想知道一种方法,它可以在任何合理兼容的类似 sh 的 shell 中工作,甚至在某些比具有 GNU 用户空间和 bash 或 dash 的 Linux PC 更晦涩的环境......"
很抱歉,我个人不是专家,但在深入研究了一些相当专业编写的 initramfs busybox 脚本后,我首先选择了以下方法,从可能传递或未传递的参数中定义重要的 shell 变量。它几乎可以在任何地方按预期工作。
这有点漂亮,因为您只有在用户没有定义变量时才将变量设置为默认条件,而无需任何额外的工作来检查它们是否确实如此。当然还有很多其他用途,我只是不够聪明,无法按我应该的方式使用它们。
_VAR1=${1:-/default/path} ; _VAR2=${2:-"$_default_size"}
EDIT3:
phs 正确地指定他的方法测试空变量而不是问题中提出的空变量。根据是否使用中心冒号,此方法可以执行相同的操作。我从下面的 POSIX 指南中复制了一个废话表来演示这一点。
{subs='substitute'; params='parameters'; assn='assign'; err='error'}
"$parameter" == |set && !null |set && null| !set
------------------ ------------- ----------- ----------
${parameter:-word} | subs params | subs word | subs word
------------------ ------------- ----------- ----------
${parameter-word} | subs params | subs null | subs word
------------------ ------------- ----------- ----------
${parameter:=word} | subs params | assn word | assn word
------------------ ------------- ----------- ----------
${parameter=word} | subs params | subs null | assn word
------------------ ------------- ----------- ----------
${parameter:?word} | subs params | err; exit | err; exit
------------------ ------------- ----------- ----------
${parameter?word} | subs params | subs null | err; exit
------------------ ------------- ----------- ----------
${parameter:+word} | subs word | subs null | subs null
------------------ ------------- ----------- ----------
${parameter+word} | subs word | subs word | subs null