bash 中 `declare -p <variable>` 的输出是否保证可重用为 shell 输入?

mur*_*uru 5 bash declare

这是专门关于bash的- 在这个答案declare中对一般情况进行了非常详尽的处理(其中提到“ // , ,的输出”,但没有提到的输出)。typesetdeclareexport -pksh93mkshzshbash

给定一个本地/导出/数组/关联数组(但可能不是 nameref)变量, infoo的输出是否保证可重用?官方文档没有提到类似的内容:declare -p foobashbash

-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.
Run Code Online (Sandbox Code Playgroud)

对于其他几个命令,-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.
Run Code Online (Sandbox Code Playgroud)

Chet Ramey 的 Bash 常见问题解答有:

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)
Run Code Online (Sandbox Code Playgroud)

但我找不到任何关于declare -p变量的信息。

Sté*_*las 5

您提到的我的答案中,其他要点之一也提到:

\n
\n

或者换句话说,只有使用“...”的才是安全的

\n
\n

其中不包括 bash 的declare -p.

\n

在我写下答案时,bash\'sdeclare -p并未用于引用标量$\'...\'变量的值,但它确实将其用于数组变量。现在情况已经改变,因为我可以看到 5.2 输出包含 BS 字符的标量变量(请参阅邮件列表上的相关讨论)。declare -x a=$\'\\b\'

\n

但是,无论如何,旧版本确实用于"..."引用标量变量的值,其中`\\是特殊的,并且这些字符具有可以作为某些语言环境中其他字符的编码的一部分找到的编码。

\n

的输出declare -p有意的(正如代码中的一些注释以及邮件列表上维护者的声明所暗示的那样)如果没有记录为可重用,但实际上仅(如果有的话)在同一版本中相同的 bash shell 和同一系统上的相同语言环境(相同的 libc 和语言环境定义)。

\n

在带有 bash 5.0.17 的 Ubuntu 20.04 上:

\n
$ a=$\'\\n\\xa3`\' bash -c \'declare -p a; echo declare -p a\' | LC_ALL=zh_CN.gb18030 bash\nbash: line 2: unexpected EOF while looking for matching ``\'\nbash: line 4: syntax error: unexpected end of file\n
Run Code Online (Sandbox Code Playgroud)\n
$ a=$\'\\n\\xa3`uname; : \\xa3`\' bash -c \'declare -p a; echo declare -p a\' | LC_ALL=zh_CN.gb18030 bash\ndeclare -x a="\n\xef\xbf\xbd\\\\Linux\\""\n
Run Code Online (Sandbox Code Playgroud)\n

unamedeclare -p当在使用 UTF-8 作为字符映射的语言环境中获得的输出被在使用 GB18030 作为字符映射的语言环境中运行的 bash 解释时,运行(幸运的是,无害) 。

\n

过去已修复了许多错误(请参阅此作为示例),其中引用未正确完成,或者declare -p(或export -pPOSIX 要求输出适合重新输入的 shell 代码)仅包括来自环境的变量定义无法映射到 shell 变量

\n

另请注意,在 bash 中,有效变量名的构成取决于区域设置。

\n
$ locale charmap\nUTF-8\n$ LC_ALL=fr_FR locale charmap\nISO-8859-1\n$ env -i $\'\\xe9=zzz\' LC_ALL=fr_FR bash -c $\'declare -p \\xe9\' | bash\nbash: line 1: declare: `\xef\xbf\xbd=zzz\': not a valid identifier\n
Run Code Online (Sandbox Code Playgroud)\n

字节 0xe9 在 ISO-8859-1 中是 \xc3\xa9,它是一个单字节[[:alpha:]],因此允许在变量名称中使用,而在 UTF-8 中,它甚至不能形成有效字符。

\n

还要注意:

\n
$ bash -c \'a=1; f() { local b=2; declare -p a b; }; f\'\ndeclare -- a="1"\ndeclare -- b="2"\n
Run Code Online (Sandbox Code Playgroud)\n

一个是全局的,一个是局部的这一事实并没有反映在declare\ 的输出中,如果两者都在函数内部使用,则生成的变量最终将成为该函数的局部变量。

\n

bashdeclare显然是模仿 ksh 的typeset(bash 也有一个typeset别名)。在 ksh86 及更早版本中,typeset -p是将输出(如果有)打印typeset到协进程(也称为双向管道)。看来它在 ksh88 中消失了。在 ksh93 中,typeset -p重新出现打印变量定义。

\n

当前版本的 ksh93 手册有

\n
\n

-p 给定 vname 的名称、属性和值以可用作 shell\n输入的形式写入标准输出。如果+p指定,则不显示值。

\n
\n

但这种说法直到2008 年才出现在 ksh93t 中

\n

-pdeclare在 1996 年发布的 2.0 中被添加到 bash 中

\n

从该版本的新闻文件中:

\n
\n

kk。`declare\' 内置命令有新选项:-a、-F、-p。

\n
\n

-F与 ksh93 不兼容)

\n

还有CWRU/changelog

\n
\n

3/24
\nbuiltins/declare.def

\n
    \n
  • 用于显示变量及其值和属性的新 -p 选项\ndeclare -p xxx显示 var 的属性和值xxx
  • \n
\n
\n

实际实现的日期是 1995 年 3 月 24 日,因此在 ksh93 之后但在 ksh93 之前,记录了它生成可重用的输出。

\n