![在 POSIX 脚本中,x=$y 是否始终等于 x="$y"?](https://linux22.com/image/211636/%E5%9C%A8%20POSIX%20%E8%84%9A%E6%9C%AC%E4%B8%AD%EF%BC%8Cx%3D%24y%20%E6%98%AF%E5%90%A6%E5%A7%8B%E7%BB%88%E7%AD%89%E4%BA%8E%20x%3D%22%24y%22%EF%BC%9F.png)
是
x=$y
和
x="$y"
总是等价的?不知道如何寻找这个。到目前为止,我一直习惯于x="$y"
“安全起见”。但我x=$1
曾经使用过并注意到,显然,我什至不需要额外的双引号。
The Open Group POSIX 文档中定义的行为在哪里?
答案1
是的,x=$y
并且x="$y"
保证在 POSIX shell 中是相同的。如果您或代码的其他读者不确定双引号在哪里必须被使用(参见什么时候需要双引号?),包括双引号可能是更安全的选择,以免造成混乱。
来自 POSIX 规范 (第 2.9.1 节 “简单命令”):
当需要执行给定的简单命令时[...],应从命令文本的开头到结尾执行以下扩展、赋值和重定向:
- 根据以下规则被识别为变量赋值或重定向的单词Shell 语法规则保存以供步骤 3 和 4 中的处理。
[...]
- 重定向应按中所述执行重定向。
- 每个变量赋值都应在赋值之前进行扩展,以进行波形符扩展、参数扩展、命令替换、算术扩展和引号删除。
注意第四点不包括场分裂或者路径名扩展(“globbing”),通常是单词出现时进行的扩展的一部分不是被识别为变量赋值。由于分配时删除了这些步骤,因此不需要引用。
也可以看看第 2.6 节“词扩展”:
单词扩展的顺序如下:
- 波形符扩展(参见波形符扩展),参数扩展(参见参数扩展),命令替换(参见命令替换)和算术展开(参见算术扩展)应从头至尾执行。请参阅第 5 项令牌识别。
- 字段分割(参见场分裂) 应当对步骤 1 生成的字段部分执行,除非
IFS
为 null。- 路径名扩展(参见路径名扩展) 须予执行,除非
set -f
已生效。- 引用删除(参见报价删除)应始终最后执行。
y
仅当inx=$y
和x="$y"
实际上是特殊参数*
or之一时,以下内容才重要@
:
请注意,由于"$@"
展开为列表对于字符串,未指定whatx=$@
和x="$@"
do,而x=$*
与 相同x="$*"
。在某些 shell 中(例如bash
, ksh93
),这样的使用与 的第一个字符是空格时$@
的使用相同,而在其他 shell(例如 busybox , , )中,它与 的设置值的第一个字符相同并使用。$*
$IFS
sh
dash
zsh
$*
$IFS
答案2
一般来说,有二可以定义变量的部分。
前导变量赋值
正如仪表板手册中对于简单命令的描述:
“名称=值”形式的前导词被删除......
换句话说, 确实 完全
x=$y
等于x="$y"
。用这样的话来说,就是第 2.9.1 节 “简单命令”遵循,并且没有应用分词或路径名扩展。由于这两个扩展是唯一可以生成新单词的扩展,因此不可能拆分包含 IFS 字符的变量或匹配多个文件名。在那里,一个单词
x=$y
将保留为一个单词。其余参数
找到代表“命令名称”的单词后,解析会发生变化,分配可能会被分割,从而变成其他东西。
bash 手册对此的描述是:
赋值语句也可以作为别名、声明、排版、导出、只读和本地内置命令(声明命令)的参数出现。
还有需要引用的地方。如同
declare x="$y"
。当然,在POSIX中,只有
export
和readonly
才有意义。现在只在 yash 中失败:
$ yash -c 'unset x; y="one two"; readonly x=$y; echo "x=$x"' x=one
所以,是的,一般来说,x=$y
和x="$y"
是完全等价的除了在某些情况下,变量赋值存在于命令名称之后。