局部变量赋值需要引号吗?

rah*_*hmu 48 shell-script quoting assignment

我可以安全地省略本地作业右侧的引号吗?

function foo {
    local myvar=${bar}
    stuff()
}
Run Code Online (Sandbox Code Playgroud)

我主要对 感兴趣bash,但欢迎提供有关其他 shell 中的边角案例的任何信息。

Sté*_*las 53

引号中需要export foo="$var"local foo="$var"(或readonlytypesetdeclare和其他变量声明命令)中:

  • dash版本 0.3.8-15 到 0.5.10.2(见变化)。
  • 所述sh的NetBSD(也是基于Almquist壳)。
  • shFreeBSD的9.2或以上的(见9.3变化
  • yash
  • zsh使用 5.1 之前的版本kshsh仿真(或export var="$(cmd)"在其他zsh情况下执行分词(不是通配))。

否则,变量扩展将受到分词和/或文件名生成的影响,就像任何其他命令的任何参数一样。

并且不需要:

  • bash
  • ksh (所有实现)
  • 所述sh的FreeBSD 9.3或更新的
  • busybox 以灰为基础sh(自 2005 年起)
  • zsh
  • dash 0.5.11 或更新版本。

在 中zsh,split+glob 永远不会在参数扩展时完成,除非 inshkshemulation,但 split(不是 glob)在命令替换时完成。从 5.1 版开始,export/local和其他声明命令已成为双关键字/内置命令,就像上面的其他 shell 一样,这意味着不需要引用,即使在sh/ksh仿真中甚至命令替换也是如此。

在某些特殊情况下,即使在这些 shell 中也需要引用,例如:

a="b=some value"
export "$a"
Run Code Online (Sandbox Code Playgroud)

或者更一般地说,如果=(包括=) 的任何剩余部分被引用或某些扩展的结果(例如export 'foo'="$var",export foo\="$var"export foo$((n+=1))="$var"$((...))实际上也应该引用)...)。或者换句话说,export如果没有export.

如果export/local命令名称本身是引用(甚至像部分"export" a="$b"'ex'port a="$b"\export a="$b"或甚至""export a="$b"),各地报价$b都需要除AT&T kshmksh以及最新版本dash

如果export/local或其中的某些部分是某些扩展(例如 incmd=export; "$cmd" a="$b"或 even export$(:) a="$b")或类似dryrun=; $dryrun export a="$b")的结果,则需要引号,但dash.

在 的情况下> /dev/null export a="$b",需要在pdksh和它的一些衍生物中使用引号。

对于command export a="$b",每个 shell 中都需要引号,但是mkshksh93、最近dashbash -o posix(具有相同的警告,commandexport不是除 之外的其他 shell 中的某些扩展的结果dash)。

编写时在任何 shell 中都不需要它们:

foo=$var export foo
Run Code Online (Sandbox Code Playgroud)

(该语法也正在与Bourne外壳,但在最新版本的兼容zsh,只有工作时sh/ksh模拟)。

(请注意,var=value local var不应使用,因为行为因壳而异)。

另请注意,export与赋值一起使用也意味着cmdin的退出状态export var="$(cmd)"丢失。照着做就export var; var=$(cmd)没有这个问题。

还要注意这种特殊情况bash

$ bash -c 'IFS=; export a="$*"; echo "$a"' bash a b
ab
$ bash -c 'IFS=; export a=$*; echo "$a"' bash a b
a b
Run Code Online (Sandbox Code Playgroud)

我的建议是总是引用。

  • 请注意,在 `zsh` 中,`local foo="$(cmd)"` 需要引号 _are_ 因为分词(但不是文件名生成)_is_ 执行未加引号的命令替换(但不是用于未加引号的参数扩展),除非启用了 `KSH_TYPESET` ,在这种情况下不需要引号。有道理?不?然后总是引用所有内容,除非您确切地知道自己在做什么。 (3认同)
  • @Matt,我喜欢你的结论。:D 很有趣,我学到的大部分 shell 脚本都是从这个 stackexchange 中学到的,所以我没有意识到 ** 总是引用你的变量** * 不是*脚本编写者的常识。我发现我有很多工作要做,由那些*没有*引用并且*不*确切知道他们在做什么的人编写的现有生产脚本...... (2认同)