【问题标题】:Do I need to quote command substitutions?我需要引用命令替换吗?
【发布时间】:2016-06-20 20:48:16
【问题描述】:

根据Google Shell Style Guide,我应该:

始终引用包含变量、命令替换、空格或 shell 元字符的字符串,除非需要小心的不带引号的扩展。

也许我误解了“命令替换”的含义,但我想知道在以下示例中是否需要使用引号:

VAR="$(echo foo bar)"

【问题讨论】:

  • 在这种情况下您不需要引号。但如果不确定,请使用引号!
  • 也许不是在那个简单的例子中,但保持一致肯定不会有坏处。但是如果foobar$foo$bar,那么我们可能需要单独引用它们。
  • 在那种特定的情况下,你不需要外引号,因为赋值会抑制字符串拆分和全局扩展。
  • 顺便说一句,VAR 是错误的形式,除非处理名称由操作系统或 shell 定义的变量。见pubs.opengroup.org/onlinepubs/009695399/basedefs/…第四段,记住环境变量和shell变量共享一个命名空间

标签: bash shell quoting


【解决方案1】:

$(echo foo bar) 确实是一个命令替换。在这个特定示例中,您不需要双引号,因为变量赋值会为其右侧创建一个“双引号上下文”,因此VAR=$(…) 等价于VAR="$(…)"

在 bash 中,export VAR=$(…)declare VAR=$(…) 中不需要双引号。但是在其他一些 sh ​​实现(例如 dash)中确实需要双引号。

env VAR=$(…) somecommandmake VAR=$(…) 等中确实需要双引号。不是等号使双引号成为可选,而是等号被 shell 解析为赋值。

a few other contexts where the double quotes are optional,但你不会错的简单规则:always use double quotes around variable and command substitutions,除非you want the split+glob operator

【讨论】:

  • 如果我们想要拆分行为而不是全局行为怎么办?也就是说,如果我们希望 Bash 拆分输出字符串而不是 glob 怎么办?这可能吗?
  • @Utku 您不能准确地说“拆分但不要通配”,但您可以使用set -f 关闭通配,然后使用不带引号的替换。使用set +f 恢复通配(或保存并恢复旧设置,如果以前可能已经关闭通配)。
【解决方案2】:

编辑:(命令替换是 $( ) 和反引号几乎等效,因此您可能正确解释它)

在 shell 脚本中通常引用字符串肯定不会有什么坏处,除非您实际上是依赖通配符等来生效。

在这个简单的例子中,当然不需要双引号,但为了保持一致性,我可能会添加它们。

如果你有

VAR=$( echo $foo $bar )

...那我肯定会同时引用变量和表达式:

VAR="$( echo "$foo" "$bar" )"

尤其是如果这些变量中的任何一个包含外部输入,或者如果您知道它们中有通配符。

编辑:正如用户@CharlesDuffy 指出的那样,这里仍然不需要外部双引号。我仍然会添加它们以与其他需要引用的变量分配保持一致。

【讨论】:

  • 相反,var=$(echo "$foo" "$bar") -- 分配仍然不需要外引号。
  • @CharlesDuffy 你是对的,但由于一致性,我再次对删除它们感到不安。哦,好吧,我会在答案中添加评论。
  • 出于一致性原因,我也这样做了。
【解决方案3】:

什么时候引用命令替换?

答案:当您希望将命令替换的输出视为单独的参数时。

示例:

我们想从.pcap 文件中提取特定的数据包(数据包编号 1、5、10 和 20)。相关命令如下:

editcap -r capture.pcap select.pcap 1 5 10 20

(Source to the command)

现在,我们要从文件中提取 随机 个数据包。为此,我们将使用来自 GNU Coreutils 的shuf

shuf -i 0-50 -n 4
8
24
20
31

上面的命令生成了 4 个 0 到 50 之间的随机数。

editcap一起使用:

editcap -r source.pcap select.pcap "$(shuf -i 0-50 -n 4)"
editcap: The specified packet number "1
34
4
38" isn't a decimal number

如您所见,引用命令替换导致shuf 的输出字符串被视为单个大字符串,包括换行符和诸如此类的东西。也就是说,加上引号导致相当于以下命令:

editcap -r source.pcap select.pcap "1
34
4
38"

相反,我们希望 Bash 将 shuf 的输出切碎,并将此切碎的输出作为单独的参数插入到 editcap。省略引号可以实现:

editcap -r source.pcap select.pcap $(shuf -i 0-50 -n 4)

【讨论】:

    【解决方案4】:

    quoting command substitutions 真正避免通配扩展:

    asterisk='*'
    echo $(echo $asterisk)
    echo $(echo "$asterisk")
    echo "$(echo $asterisk)"
    echo "$(echo "$asterisk")"
    

    【讨论】:

      猜你喜欢
      • 2014-10-03
      • 2011-07-03
      • 2021-03-13
      • 1970-01-01
      • 2021-09-10
      • 2011-04-16
      • 2013-09-16
      • 2015-01-11
      相关资源
      最近更新 更多