在变量赋值的 RHS 上引用与不引用变量

问题描述 投票:0回答:5

在 shell 脚本中,将一个变量分配给另一个变量时,这两者有什么区别:

a=$b

a="$b"

我什么时候应该使用一个而不是另一个?

bash syntax quoting
5个回答
8
投票

我觉得这里没有太大区别。是的,建议在引用变量时用双引号将变量括起来。但是,

$x
似乎没有在您的问题中被引用。

y=$x
本身不会影响空格的处理方式。只有在实际使用
$y
时,引用才有意义。例如:

$ x=" a    b "
$ y=$x
$ echo $y
a b
$ echo "$y"
 a    b

8
投票

来自 POSIX shell 语法规范的 section 2.9.1

每个变量赋值都应在赋值之前进行波浪号扩展、参数扩展、命令替换、算术扩展和引用删除

字符串拆分和通配符(双引号抑制的步骤)不在此列表中,其他在变量扩展期间不相关(波浪线扩展,例如,需要在被解析的源代码中使用波浪线,而不是在变量的内容中)。

因此,引号在所有简单的赋值中都是多余的(这里不是指那些使用

declare
export
或类似命令的参数实现的赋值),除了那些 (1) 单引号而不是双引号的行为,需要字符串;或 (2) 值中的空格或其他内容将被解析为句法而非文字。


(请注意,关于如何解析命令的决定——因此,无论它是赋值、简单命令、复合命令还是其他东西——发生在before参数扩展;因此,

var=$1
是在
$1
的值被考虑之前确定是一个赋值!如果这是不真实的,这样数据可以悄悄地变成语法,那么在 bash 中编写处理不受信任数据的安全代码将更加困难 - 如果不是不可能的话).


6
投票

当单独用作语句时,没有(充分)理由对变量赋值的 RHS 进行双引号。

赋值语句的 RHS 不受分词(或大括号扩展)等的影响,因此不需要引号即可正确赋值。所有其他扩展(据我所知)确实出现在 RHS 上,但也出现在双引号中,因此引用没有任何意义。

话虽这么说,但有理由引用RHS。即如何解决 Bash 命令替换中的错误“bash: !d': event not found”(具体参见我的回答和 rici 的回答)。


2
投票

以下是一些其他示例:(在当前目录中有两个文件

t.sh
file

a='$(ls)'        # no command substitution
b="$(ls)"        # command substitution, no word splitting
c='*'            # no filename expansion
d="*"            # no filename expansion
e=*              # no filename expansion
f=$a             # no expansions or splittings
g="$a"           # no expansions or splittings
h=$d             # no expansions or splittings

echo ---'$a'---
echo $a          # no command substitution
echo ---'$b'---
echo $b          # word splitting
echo ---'"$b"'---
echo "$b"        # no word splitting
echo ---'$c'---
echo $c          # filename expansion, word splitting
echo ---'"$c"'---
echo "$c"        # no filename expansion, no word splitting
echo ---'$d'---
echo $d          # filename expansion, word splitting
echo ---'"$d"'---
echo "$d"        # no filename expansion, no word splitting
echo ---'"$e"'---
echo "$e"        # no filename expansion, no word splitting 
echo ---'$e'---
echo $e          # filename expansion, word splitting
echo ---'"$f"'---
echo "$f"        # no filename expansion, no word splitting 
echo ---'"$g"'---
echo "$g"        # no filename expansion, no word splitting
echo ---'$h'---
echo $h          # filename expansion, word splitting
echo ---'"$h"'---
echo "$h"        # no filename expansion, no word splitting

输出:

---$a---
$(ls)
---$b---
file t.sh
---"$b"---
file
t.sh
---$c---
file t.sh
---"$c"---
*
---$d---
file t.sh
---"$d"---
*
---"$e"---
*
---$e---
file t.sh
---"$f"---
$(ls)
---"$g"---
$(ls)
---$h---
file t.sh
---"$h"---
*

需要注意的一件有趣的事情是,如果变量赋值用双引号引起来,并且 RHS 显式给出为

"$(ls)"
而不是隐式为
"$a"
..

,则命令替换会发生在变量赋值中

1
投票

高级 Bash 脚本指南:第 5 章:引用

引用变量时,是 通常建议附上其 双引号中的名称。这可以防止 所有特殊的重新解释 引号字符串中的字符。 使用双引号来防止单词 分裂。一个参数包含在 双引号将自己呈现为 单个词,即使它包含 空格分隔符。

© www.soinside.com 2019 - 2024. All rights reserved.