在 POSIX 脚本中,x=$y 是否始终等于 x="$y"?

在 POSIX 脚本中,x=$y 是否始终等于 x="$y"?

x=$y

x="$y"

总是等价的?不知道如何寻找这个。到目前为止,我一直习惯于x="$y"“安全起见”。但我x=$1曾经使用过并注意到,显然,我什至不需要额外的双引号。

The Open Group POSIX 文档中定义的行为在哪里?

答案1

是的,x=$y并且x="$y"保证在 POSIX shell 中是相同的。如果您或代码的其他读者不确定双引号在哪里必须被使用(参见什么时候需要双引号?),包括双引号可能是更安全的选择,以免造成混乱。

来自 POSIX 规范 (第 2.9.1 节 “简单命令”):

当需要执行给定的简单命令时[...],应从命令文本的开头到结尾执行以下扩展、赋值和重定向:

  1. 根据以下规则被识别为变量赋值或重定向的单词Shell 语法规则保存以供步骤 3 和 4 中的处理。

[...]

  1. 重定向应按中所述执行重定向
  2. 每个变量赋值都应在赋值之前进行扩展,以进行波形符扩展、参数扩展、命令替换、算术扩展和引号删除。

注意第四点不包括场分裂或者路径名扩展(“globbing”),通常是单词出现时进行的扩展的一部分不是被识别为变量赋值。由于分配时删除了这些步骤,因此不需要引用。

也可以看看第 2.6 节“词扩展”

单词扩展的顺序如下:

  1. 波形符扩展(参见波形符扩展),参数扩展(参见参数扩展),命令替换(参见命令替换)和算术展开(参见算术扩展)应从头至尾执行。请参阅第 5 项令牌识别
  2. 字段分割(参见场分裂) 应当对步骤 1 生成的字段部分执行,除非IFS为 null。
  3. 路径名扩展(参见路径名扩展) 须予执行,除非set -f已生效。
  4. 引用删除(参见报价删除)应始终最后执行。

y仅当inx=$yx="$y"实际上是特殊参数*or之一时,以下内容才重要@

请注意,由于"$@"展开为列表对于字符串,未指定whatx=$@x="$@"do,而x=$*与 相同x="$*"。在某些 shell 中(例如bash, ksh93),这样的使用与 的第一个字符是空格时$@的使用相同,而在其他 shell(例如 busybox , , )中,它与 的设置值的第一个字符相同并使用。$*$IFSshdashzsh$*$IFS

答案2

一般来说,有可以定义变量的部分。

  • 前导变量赋值

    正如仪表板手册中对于简单命令的描述:

    “名称=值”形式的前导词被删除......

    换句话说, 确实 完全x=$y等于x="$y"

    用这样的话来说,就是第 2.9.1 节 “简单命令”遵循,并且没有应用分词或路径名扩展。由于这两个扩展是唯一可以生成新单词的扩展,因此不可能拆分包含 IFS 字符的变量或匹配多个文件名。在那里,一个单词x=$y将保留为一个单词。

  • 其余参数

    找到代表“命令名称”的单词后,解析会发生变化,分配可能会被分割,从而变成其他东西。

    bash 手册对此的描述是:

    赋值语句也可以作为别名、声明、排版、导出、只读和本地内置命令(声明命令)的参数出现。

    还有需要引用的地方。如同declare x="$y"

    当然,在POSIX中,只有exportreadonly才有意义。

    现在只在 yash 中失败:

    $ yash -c 'unset x; y="one two"; readonly x=$y; echo "x=$x"'
    x=one
    

所以,是的,一般来说,x=$yx="$y"是完全等价的除了在某些情况下,变量赋值存在于命令名称之后。

相关内容