局部变量赋值是否需要引号?


36

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

function foo {
    local myvar=${bar}
    stuff()
}

我主要感兴趣 bash,但是欢迎提供有关其他外壳中角套的任何信息。


我认为,如果将它放在一行中就像您在函数中使用它一样,没有什么区别。作业不需要报价。参见mpi-sb.mpg.de/departments/rg1/teaching/unixffb-ss98/…–
jirib

Answers:


41

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

  • dash
  • 所述sh的NetBSD(也是基于Almquist壳)。
  • shFreeBSD的9.2或以上的(见9.3变化
  • yash
  • zshksh或在5.1之前的版本中sh(或在export var="$(cmd)"其中zsh进行仿真(否则将在其中执行分词的地方(不会出现乱码)))。

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

并且不需要在:

  • bash
  • ksh (所有实现)
  • 所述sh的FreeBSD 9.3或更新的
  • busybox基于灰烬sh(自2005年起)
  • zsh

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

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

a="b=some value"
export "$a"

或者更一般地,如果什么事的=(包括=)是引用或者一些扩展的结果(如export 'foo'="$var"export foo\="$var"export foo$((n+=1))="$var"(这$((...))也应该实际报价)...)。或者换句话说,export如果不带编写参数,则to的参数将不是有效的变量赋值export

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

如果export/ local或其中的一部分是某种扩展的结果(例如in cmd=export; "$cmd" a="$b"或什至export$(:) a="$b")或诸如dryrun=; $dryrun export a="$b")之类的东西,则在每个shell中都需要使用引号。

在的情况下> /dev/null export a="$b"pdksh以及其中的一些派生词都需要使用引号。

对于command export a="$b",每个shell中都需要加引号,但必须mksh加上和ksh93(带有相同的警告command,但export不是某些扩展的结果)。

编写它们时,不需要在任何shell中使用它们:

foo=$var export foo

(该语法也与Bourne Shell兼容,但在的最新版本中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

我的建议是总是报价。


3
请注意,在zsh报价需要local foo="$(cmd)",因为wordsplitting(而不是文件名生成)用于不带引号的命令替换执行(但不包括未加引号的参数扩展),除非KSH_TYPESET已启用,在这种情况下,报价没有必要的。说得通?没有?然后始终引用所有内容,除非您确切地知道自己在做什么。
马特

2
@马特,我爱你的结论。:D有趣的是,我学到的大多数关于Shell脚本的知识都来自于这个stackexchange,所以我没有意识到在脚本编写者中常引用变量常见的。我发现我有很多固定工作要做通过现有的人谁写的剧本生产的没有报价,并且知道他们在做什么...
通配符

3

我通常会引用变量的任何用法,因为这些变量可能存在诸如空格之类的字符。否则,您将遇到以下问题:

#!/bin/bash

bar="hi bye"

function foo {
  local myvar=${bar}
  printf "%s\n" $myvar
  printf "%s\n" "$myvar"
}

foo

变量中的变量用法似乎不需要引号,但是当您使用它时(例如在变量中),则需要在引号中加引号printf

  printf "%s\n" "$myvar"

注意:请记住,变量$IFS是控制分隔符是什么的变量。

IFS    The  Internal  Field  Separator that is used for word splitting after 
       expansion and to split lines into words with the read builtin command. 
       The default value is ``<space><tab><newline>''.

在Bash中启用调试后,我们可以看到幕后发生的事情。

$ bash -x cmd.bash 
+ bar='hi bye'
+ foo
+ local 'myvar=hi bye'
+ printf '%s\n' hi bye
hi
bye
+ printf '%s\n' 'hi bye'
hi bye

在上面的代码中,我们可以看到变量$bar已经很好地传递了,$myvar但是当我们使用它时,我们必须知道使用它时$myvar的内容$myvar


2
分词是不带引号的变量是唯一的问题,你必须要考虑的文件名代(又名通配符)以及(尽管这(两)不变量赋值和应用bash,并kshlocal/ typeset...特殊建宏)。
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.