这是专门关于bash
的declare
- 一般情况在这个答案(其中提到“ typeset
// , declare
,的export -p
输出” ksh93
,但是mksh
zsh
不是的那个bash
)。
给定一个本地/导出/数组/关联数组(但可能不是 nameref)变量, infoo
的输出是否保证可重用?这declare -p foo
bash
bash
官方文档没有提到类似的事情:
该
-p
选项将显示每个的属性和值name
。当-p
与参数一起使用时name
,除-f
和之外的其他选项-F
将被忽略。
我看了看这CHANGES
,并看到了这个关于功能:
This document details the changes between this version, bash-2.05-beta1,
and the previous version, bash-2.05-alpha1.
...
b. When `set' is called without options, it prints function definitions in a
way that allows them to be reused as input. This affects `declare' and
`declare -p' as well.
对于其他几个命令,-p
旨在生成可重用的输出:
s. The `shopt' `-p' option now causes output to be displayed in a reusable
format.
...
u. `umask' now has a `-p' option to print output in a reusable format.
Bash-2.0 contained extensive changes and new features from bash-1.14.7.
Here's a short list:
...
most builtins use -p option to display output in a reusable form
(for consistency)
但我找不到任何关于declare -p
变量的信息。
答案1
那时你所指的我的答案,另外一点也提到:
或者换句话说,只有那些使用“...”的才是安全的
其中不包括 bash 的declare -p
.
当时我写的答案bash
没有declare -p
用于$'...'
引用值标量变量,但它确实将其用于数组变量。现在情况已经改变,因为我可以看到 5.2 输出declare -x a=$'\b'
包含 BS 字符的标量变量(请参阅邮件列表中的相关讨论)。
但是,无论如何,旧版本确实用于"..."
引用标量变量的值,其中`
和\
是特殊的,并且这些字符具有可以作为某些语言环境中其他字符的编码的一部分找到的编码。
的输出declare -p
是故意的(作为代码中的一些注释还有作为维护者在邮件列表上的声明建议)如果没有记录为可重用,但实际上(如果有的话)仅在同一 bash shell 的同一版本和同一系统上的同一语言环境中(相同的 libc 和语言环境定义)。
在带有 bash 5.0.17 的 Ubuntu 20.04 上:
$ a=$'\n\xa3`' bash -c 'declare -p a; echo declare -p a' | LC_ALL=zh_CN.gb18030 bash
bash: line 2: unexpected EOF while looking for matching ``'
bash: line 4: syntax error: unexpected end of file
$ a=$'\n\xa3`uname; : \xa3`' bash -c 'declare -p a; echo declare -p a' | LC_ALL=zh_CN.gb18030 bash
declare -x a="
�\\Linux\""
uname
declare -p
当在使用 UTF-8 作为字符映射的语言环境中获得的输出由在使用 GB18030 作为字符映射的语言环境中运行的 bash 解释时,运行(幸运的是,无害) 。
一些错误(参见这或者这作为示例)过去已修复引用未正确完成的问题,或者declare -p
(或者export -p
POSIX 要求输出适合重新输入的 shell 代码)本身就包含了无法映射到 shell 变量的环境变量的定义。
另请注意,在 bash 中,有效变量名的构成取决于区域设置。
$ locale charmap
UTF-8
$ LC_ALL=fr_FR locale charmap
ISO-8859-1
$ env -i $'\xe9=zzz' LC_ALL=fr_FR bash -c $'declare -p \xe9' | bash
bash: line 1: declare: `�=zzz': not a valid identifier
字节 0xe9 在 ISO-8859-1 中是 é,它是一个单字节,[[:alpha:]]
因此允许在变量名称中使用,而在 UTF-8 中,它甚至不能形成有效字符。
还要注意:
$ bash -c 'a=1; f() { local b=2; declare -p a b; }; f'
declare -- a="1"
declare -- b="2"
一个是全局的,一个是局部的这一事实并未反映在 的declare
输出中,如果两者都在函数内部使用,则生成的变量最终将成为该函数的局部变量。
bashdeclare
显然是仿照 ksh 的typeset
(bash 也有一个typeset
别名)。在 ksh86 及更早版本中,typeset -p
是将typeset
输出(如果有)打印到协进程(又名双向管)。看来它在 ksh88 中消失了。在 ksh93 中,typeset -p
重新出现打印变量定义。
-p
给定 vname 的名称、属性和值以可用作 shell 输入的形式写入标准输出。如果+p
指定,则不显示值。
但仅此而已2008年出现在ksh93t。
-p
declare
在 1996 年发布的 2.0 中被添加到 bash 中
从该版本的新闻文件中:
kk。 `declare' 内置命令有新选项:-a、-F、-p。
(-F
与 ksh93 不兼容)
还有CWRU/changelog
:
3/24
内置函数/declare.def
- 用于显示变量及其值和属性的新 -p 选项
declare -p xxx
显示 var 的 attribs 和值xxx
实际实现日期为 1995 年 3 月 24 日,因此在 ksh93 之后但在 ksh93 之前,记录了它生成可重用的输出。
答案2
Bash 的很多功能都是从 Ksh 复制的。作为 bash 和 ksh 下具有相同功能的相同开关,那么应该预期 Ksh 答案也适用于 Bash。
我个人的理解是, 的输出declare -p
是可重用的,而且我还没有见过不可以重用的情况。