在变量赋值的右侧引用变量与不引用变量

发布于 2024-09-28 06:41:44 字数 146 浏览 11 评论 0原文

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

a=$b

以及

a="$b"

何时应该使用其中一个而不是另一个?

In shell scripting, what is the difference between these two when assigning one variable to another:

a=$b

and

a="$b"

and when should I use one over the other?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

浪推晚风 2024-10-05 06:41:44

我认为这里没有什么大的区别。是的,建议在引用变量时将变量括在双引号中。但是,您的问题中似乎没有引用 $x

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

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

I think there is no big difference here. Yes, it is advisable to enclose a variable in double quotes when that variable is being referenced. However, $x does not seem to be referenced here in your question.

y=$x does not by itself affect how whitespaces will be handled. It is only when $y is actually used that quoting matters. For example:

$ x=" a    b "
$ y=$x
$ echo $y
a b
$ echo "$y"
 a    b
作妖 2024-10-05 06:41:44

来自 POSIX shell 语法规范的 第 2.9.1 节

在分配值之前,每个变量分配都应进行扩展以进行波形符扩展、参数扩展、命令替换、算术扩展和引号删除

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

因此,引号在所有简单赋值中都是多余的(这里不是指那些使用 declareexport 或类似命令的参数实现的赋值),除了那些 (1) 的行为需要单引号而不是双引号的字符串; (2) 值中的空格或其他内容将被解析为语法而不是文字。


(请注意,如何解析命令的决定——因此,无论它是赋值、简单命令、复合命令还是其他命令——发生在参数扩展之前;因此,在考虑 $1 的值之前,var=$1 被确定为赋值!如果这是不正确的,那么数据可能会默默地变成语法,那就太远了!在 bash 中编写处理不受信任数据的安全代码会更加困难(如果不是不可能的话)。

From section 2.9.1 of the POSIX shell syntax specification:

Each variable assignment shall be expanded for tilde expansion, parameter expansion, command substitution, arithmetic expansion, and quote removal prior to assigning the value.

String-splitting and globbing (the steps which double quotes suppress) are not in this list, and the others aren't relevant during variable expansion (tilde expansion, for example, requires a tilde in the source code being parsed, not in the contents of a variable).

Thus, the quotes are superfluous in all simple assignments (not speaking here to those implemented with arguments to declare, export or similar commands) except those where (1) the behavior of single-quoted, not double-quoted, strings are desired; or (2) whitespace or other content in the value would be otherwise parsed as syntactic rather than literal.


(Note that the decision on how to parse a command -- thus, whether it is an assignment, a simple command, a compound command, or something else -- takes place before parameter expansions; thus, var=$1 is determined to be an assignment before the value of $1 is ever considered! Were this untrue, such that data could silently become syntax, it would be far more difficult -- if not impossible -- to write secure code handling untrusted data in bash).

燃情 2024-10-05 06:41:44

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

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

话虽这么说,但有理由引用 RHS。即如何解决错误Bash 命令替换中的“bash:!d':未找到事件”(具体请参阅我的答案和 rici 的答案)。

There are no (good) reasons to double quote the RHS of a variable assignment when used as a statement on its own.

The RHS of an assignment statement is not subject to word splitting (or brace expansion), etc. so cannot need quotes to assign correctly. All other expansions (as far as I'm aware) do occur on the RHS but also occur in double quotes so the quoting serves no purpose.

That being said there are reasons not to quote the RHS. Namely how to address error "bash: !d': event not found" in Bash command substitution (specifically see my answer and rici's answer).

红衣飘飘貌似仙 2024-10-05 06:41:44

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

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"..

Here are some other examples: ( having two files in the current directory t.sh and 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

Output:

---$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"---
*

One interesting thing to notice is that command substitution occurs in variable assignments if they are in double quotes, and if the RHS is given explicitly as "$(ls)" and not implicitly as "$a"..

好久不见√ 2024-10-05 06:41:44

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

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

Advanced Bash-Scripting Guide: Chapter 5: Quoting

When referencing a variable, it is
generally advisable to enclose its
name in double quotes. This prevents
reinterpretation of all special
characters within the quoted string.
Use double quotes to prevent word
splitting. An argument enclosed in
double quotes presents itself as a
single word, even if it contains
whitespace separators.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文