bash中声明的和null(空)的定义不一致? 介绍
我试图测试是否声明了一个变量,但没有赋值 根据(引用POSIX规范),声明意味着指定变量的类型,而设置意味着为其赋值。null(空字符串)被视为有效值 实验 然而,仅声明变量也会为其分配一个空字符串:bash中声明的和null(空)的定义不一致? 介绍,bash,Bash,我试图测试是否声明了一个变量,但没有赋值 根据(引用POSIX规范),声明意味着指定变量的类型,而设置意味着为其赋值。null(空字符串)被视为有效值 实验 然而,仅声明变量也会为其分配一个空字符串: declare var_a [ -n "${var_a+set}" ] && echo "var_a is set to \"$var_a\"" 将其复制/粘贴到终端中,输出为:var\u a设置为“” 在不设置数组的情况下声明数组根据上述定义正常工作: declare -a v
declare var_a
[ -n "${var_a+set}" ] && echo "var_a is set to \"$var_a\""
将其复制/粘贴到终端中,输出为:var\u a设置为“”
在不设置数组的情况下声明数组根据上述定义正常工作:
declare -a var_b
[ -n "${var_b+set}" ] && echo "var_b is set to \"$var_b\""
这不会给出任何输出
即使使用此语法声明数组,也不会设置它:
var_c=()
[ -n "${var_c+set}" ] && echo "var_c is set to \"$var_c\""
但是设置一个变量,然后再次取消设置它似乎实际上是“取消声明”:
这里最后一条语句的输出是:var\u d未声明
最后,基于这些实验,我认为声明一个局部变量(在函数中),然后取消设置它,然后再次赋值,实际上会使它成为一个全局变量(因为它是“未声明的”):
仅验证declare
和local
在工作方式上是否相似(这意味着声明“该选项可以是declare
接受的任何选项”):
这里最后一条语句的输出是:var\u f未声明
问题
我想知道我的理解是否不完整,或者bash在这方面不一致
PS:上面的代码示例可以简单地复制/粘贴到终端会话中(如果您愿意,可以全部在同一会话中)我不回答您的所有问题。但是,仅声明标量变量不会为其赋值: 这将包括3种情况:未设置、设置但为空、设置值
if [[ -n ${foo+unset} ]]; then
if [[ -n $foo ]]; then
echo foo is not empty
else
echo foo is empty
fi
else
echo foo is unset
fi
简单地声明一个变量不会给它一个值:
$ unset foo
$ if [[ -n ${foo+unset} ]]; then if [[ -n $foo ]]; then echo foo is not empty; else echo foo is empty; fi; else echo foo is unset; fi
foo is unset
$ declare foo
$ if [[ -n ${foo+unset} ]]; then if [[ -n $foo ]]; then echo foo is not empty; else echo foo is empty; fi; else echo foo is unset; fi
foo is unset
$ foo=
$ if [[ -n ${foo+unset} ]]; then if [[ -n $foo ]]; then echo foo is not empty; else echo foo is empty; fi; else echo foo is unset; fi
foo is empty
$ foo=x
$ if [[ -n ${foo+unset} ]]; then if [[ -n $foo ]]; then echo foo is not empty; else echo foo is empty; fi; else echo foo is unset; fi
foo is not empty
我看不到“var_a设置为”“”——您确定这样做时有一个“干净”的外壳吗?当我在macOS的终端应用程序中打开一个新选项卡并粘贴第一个示例的行时,
var\u a被设置为“
”,作为输出;这是一个干净的shell,还是我应该采取其他步骤使其干净?实际上,当我打开一个新选项卡并仅粘贴[-n“${var\u a+set}]”和&echo“var\u a”设置为\“$var\u a\”
时,我不会得到输出。所以我想当我运行bash--version
时,我的shell是干净的,顺便说一句,我得到了GNUBash,版本3.2.57(1)-发行版(x86_64-apple-darwin16)
。也许这就不同了?是的,事实上是这样的:当我用GNUBash,版本4.4.12(1)-发行版尝试这一点时,它按预期工作。结果是GNUBash 4.4.12
按预期工作,而GNUBash 3.2.57
(默认安装在macOS Sierra中)则没有。感谢你指出这个定义实际上是正确的。格伦·杰克曼,你的问题含蓄地回答了问题1-3;您是否也知道如何可靠地确定变量在任何bash版本中是否未设置?这也可以回答问题4。有bash版本吗?这是POSIX参数扩展语法,不同的版本有不同的行为。我们正在研究bug修复,您不希望必须按照自己的方式编写历史bug代码。你试图解决的问题真的对未设置与设置那么敏感,但却是空的吗?我没有意识到这一点,也明白你的意思;这是一个用于调试/故障排除的布尔函数,我要求提供任何bash版本(我实际上是指兼容POSIX的版本),因为我不想在不同的机器上使用不同的shell运行它时,对意外的结果感到惊讶;自从我上次发表评论以来,我意识到我可以简单地在脚本的开头添加一个前提条件检查,如果它是未经测试的版本,则该检查将失败,要求首先测试是否成功,如果成功,则包括该版本。问题4实际上与是否设置了变量无关<代码>声明
不创建变量;它设置名称的属性declare-a foo
仅设置名称foo
上的数组属性<代码>声明栏
实际上没有任何作用。异常出现在函数内部,其中declare
隐式地使名称成为本地名称,这与使用local
命令相同。
function anotherFunction() {
local var_f
[[ $(declare | grep ^var_f) ]] && echo "var_f is declared" || echo "var_f is not declared" # --> declared
var_f=some_value
[[ $(declare | grep ^var_f) ]] && echo "var_f is declared" || echo "var_f is not declared" # --> declared
unset var_f
[[ $(declare | grep ^var_f) ]] && echo "var_f is declared" || echo "var_f is not declared" # --> not declared
}
# local can only be used in a function, hence the function call
anotherFunction
if [[ -n ${foo+unset} ]]; then
if [[ -n $foo ]]; then
echo foo is not empty
else
echo foo is empty
fi
else
echo foo is unset
fi
$ unset foo
$ if [[ -n ${foo+unset} ]]; then if [[ -n $foo ]]; then echo foo is not empty; else echo foo is empty; fi; else echo foo is unset; fi
foo is unset
$ declare foo
$ if [[ -n ${foo+unset} ]]; then if [[ -n $foo ]]; then echo foo is not empty; else echo foo is empty; fi; else echo foo is unset; fi
foo is unset
$ foo=
$ if [[ -n ${foo+unset} ]]; then if [[ -n $foo ]]; then echo foo is not empty; else echo foo is empty; fi; else echo foo is unset; fi
foo is empty
$ foo=x
$ if [[ -n ${foo+unset} ]]; then if [[ -n $foo ]]; then echo foo is not empty; else echo foo is empty; fi; else echo foo is unset; fi
foo is not empty