使用 bash 4.3,手册和实际行为之间似乎存在差异:
unset string # just to be sure
declare string # $? is 0 afterwards
declare -p string # fails, 'string: not found'
printf %b "${string-unset}" "\n" # consequently, yields unset
内置声明/排版的手册部分没有声明需要在声明时进行赋值。相反,该declare [...] [...] name[=value]
符号暗示这应该是合法的。
我缺少什么,它是“设置”变量的含义的定义吗?我是否误读了手册的“参数扩展”部分,它至少使用了术语“未设置”?或者这只是特定于版本的奇怪现象?
答案1
在 bash 版本高达 3.2 的情况下,顺序为:
$ declare string; declare -p string
打印declare -- string=""
,这表明变量被设置为空字符串。
在版本 4.1、4.2 和 4.3 上,该变量没有设置为任何内容,这实际上会引发错误:
$ declare string; declare -p string
bash: declare: string: not found
在 bash 4.4 上解决:
$ declare string; declare -p string
declare -- string
这意味着字符串已被声明,但尚未为其分配任何值(甚至不是 null)。
答案2
事实上,对参数/变量含义的假设是未设置OP中的内容不精确。
man bash
将变量定义为特殊类型的参数。因此,有关变量的信息有时位于仅涉及一般参数的部分中。
描述变量的一般术语
描述变量特征和状态的术语维基百科关于变量的文章。
- 声明状态: 内存被保留,名称存在
- 初始化状态:除了1.之外,还赋值(声明后直接)
- 未初始化状态:值未定义,未设置初始值(仅发生了声明)
- 无效的value:某些编程语言返回的保留/特殊值,用于指示未初始化的变量
bash 手册中与变量相关的条目
- 设置状态:“如果参数已被赋值,则该参数已被设置。” [参数部分]
- 未设置状态,模棱两可,似乎适用于不存在/不再存在的变量以及根据一般术语处于“未初始化状态”的变量:“...bash 测试未设置的参数...”[参数扩展段]
- 空/空字符串- 空值:“如果参数已被赋值,则该参数被设置。空字符串是有效值。” [参数部分]
- 未设置内置- 命令“消灭”变量,例如
unset string
:“对于每个名称,删除相应的变量...”[SHELL BUILTIN COMMANDS 部分,'unset' 段落] - 声明内置- 例如
declare -p string
:“-p 选项将显示每个名称的属性和值。” [SHELL BUILTIN COMMANDS 部分,'声明'/'排版' 段落]
重新陈述并回答原来的问题
这个问题应该更准确地表述为:“如何区分未初始化的 bash 变量和不存在的变量?”
对此的答案是:
不要对此感到困惑
unset
内置从存在中删除一个变量并在其中删除一个变量未设置状态在 bash 术语中,它要么尚未声明,要么已声明为无值。declare
对于已声明为无值的变量,内置命令在 bash 4.3 与 bash 4.4 中的行为确实不一致:$ # bash 4.3 $ unset string; declare string; declare -p string; echo $? bash: declare: string: not found 1 $ # bash 4.4 $ unset string; declare string; declare -p string; echo $? declare -- string 0
因此,这种测试正在使用的单个变量名称的方法并不通用,但似乎在最近的 bash 版本中有效。
不幸的是,参数扩展无助于区分不存在的变量和未初始化的变量,因为这两种情况都包含在相同的变量中。未设置状态:
$ declare string; echo ${string-UNSET} # `string` exists, empty UNSET $ unset string; echo ${string-UNSET} # `string` does not exist UNSET
不幸的是,条件运算符也
-v
没有帮助[手册部分 CONDITIONAL EXPRESSIONS],它测试“shell 变量 VARNAME 是否已设置(已分配值)”,而不指示 VARNAME 是否存在:$ unset string; ! [ -v string ] && echo "unused" unused $ declare string; ! [ -v string ] && echo "unused" unused
相关话题
讨论重点介绍与参数/变量状态和值相关的术语混淆和 bash 细节: