【问题标题】:Quoting vs not quoting the variable on the RHS of a variable assignment在变量赋值的 RHS 上引用与不引用变量
【发布时间】:2011-04-26 21:34:41
【问题描述】:

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

a=$b

a="$b"

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

【问题讨论】:

标签: bash syntax quoting


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

    当单独用作语句时,没有(很好的)理由将变量赋值的 RHS 双引号。

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

    话虽如此,有理由引用 RHS。即how to address error "bash: !d': event not found" in Bash command substitution(具体看我的回答和rici的回答)。

    【讨论】:

      【解决方案3】:

      来自 POSIX shell 语法规范的section 2.9.1

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

      字符串拆分和通配符(双引号抑制的步骤)不在此列表中。

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


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

      【讨论】:

        【解决方案4】:

        以下是一些其他示例:(在当前目录中有两个文件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"..

        【讨论】:

        • 这些示例不会改变引号是否存在 作业,这是 OP 询问的情况。
        • 也就是说,这里的问题是a="$(ls)"a=$(ls)是否不同,而不是echo "$a"echo $a是否不同。
        【解决方案5】:

        Advanced Bash-Scripting Guide: Chapter 5: Quoting

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

        【讨论】:

        • 一般来说这是一个很好的建议,但在 OP 提到的特定情况下,引用没有任何意义。
        • 确实,这通常是很好的建议(来自 ABS 的建议几乎令人惊讶,因为它倾向于提出不太好的建议并忽略良好实践),但与问题无关被问到。
        • 你会推荐什么指南?
        • @JacobLee Bash Hackers Wiki tutorials listing 目前给Greg's Bash wiki's tutorialSteve Parker's shell scripting guide 的得分最高。 ABS 处于“谨慎使用”的中间位置。
        • @dogbane,你会反对切换到不同参考源的编辑吗?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-10
        • 2016-12-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多