我认为Vinko 的answer 暗示了(如果没有说明)您所追求的答案,尽管它没有简单地拼写出来。要区分 VAR 是否设置但为空或未设置,您可以使用:
if [ -z "${VAR+xxx}" ]; then echo "VAR is not set at all"; fi
if [ -z "$VAR" ] && [ "${VAR+xxx}" = "xxx" ]; then echo "VAR is set but empty"; fi
您可能可以将第二行的两个测试合二为一:
if [ -z "$VAR" -a "${VAR+xxx}" = "xxx" ]; then echo "VAR is set but empty"; fi
但是,如果您阅读 Autoconf 的文档,您会发现他们不建议将术语与“-a”结合使用,而是建议将单独的简单测试与&& 结合使用。我没有遇到有问题的系统;这并不意味着它们过去不存在(但它们现在可能极为罕见,即使它们在遥远的过去并不那么罕见)。
您可以在 Bash 手册中找到这些以及其他相关的shell parameter expansions、test or [ 命令和conditional expressions 的详细信息。
最近有人通过电子邮件向我询问这个问题的答案:
您使用了两个测试,我很了解第二个,但不是第一个。更确切地说,我不明白变量扩展的必要性
if [ -z "${VAR+xxx}" ]; then echo "VAR is not set at all"; fi
这不也能达到同样的效果吗?
if [ -z "${VAR}" ]; then echo "VAR is not set at all"; fi
公平的问题 - 答案是“不,您更简单的替代方案不会做同样的事情”。
假设我在你的测试之前写了这个:
VAR=
您的测试会说“根本没有设置 VAR”,但我的测试会说(暗示因为它没有回显)“VAR 已设置,但它的值可能为空”。试试这个脚本:
(
unset VAR
if [ -z "${VAR+xxx}" ]; then echo "JL:1 VAR is not set at all"; fi
if [ -z "${VAR}" ]; then echo "MP:1 VAR is not set at all"; fi
VAR=
if [ -z "${VAR+xxx}" ]; then echo "JL:2 VAR is not set at all"; fi
if [ -z "${VAR}" ]; then echo "MP:2 VAR is not set at all"; fi
)
输出是:
JL:1 VAR 根本没有设置
MP:1 VAR 根本没有设置
MP:2 VAR 根本没有设置
在第二对测试中,变量被设置,但它被设置为空值。这就是 ${VAR=value} 和 ${VAR:=value} 符号的区别。 ${VAR-value} 和 ${VAR:-value},${VAR+value} 和 ${VAR:+value},等等。
正如Gili 在他的answer 中指出的那样,如果您使用set -o nounset 选项运行bash,那么上面的基本答案会因unbound variable 而失败。它很容易补救:
if [ -z "${VAR+xxx}" ]; then echo "VAR is not set at all"; fi
if [ -z "${VAR-}" ] && [ "${VAR+xxx}" = "xxx" ]; then echo "VAR is set but empty"; fi
或者您可以使用set +u 取消set -o nounset 选项(set -u 相当于set -o nounset)。