Bash中反引号和大括号的区别

112

当我要回答这个问题时,我本打算使用${}符号,因为我在这里看到过很多次,人们认为它比反引号更好。

然而,当我尝试使用${}时,它并不像我预期的那样工作。最后,我不得不回到传统的反引号。

joulesFinal=${echo $joules2 \* $cpu | bc}

我收到了这条消息。

-bash: ${echo $joules * $cpu | bc}: bad substitution

但是。
joulesFinal=`echo $joules2 \* $cpu | bc`

运行良好。那么我需要做哪些其他更改呢?


对于简单的算术运算,只需使用Bash的内置功能。joulesFinal=$((joules2 * cpu)) - tripleee
@tripleee,原始问题涉及非整数算术,因此内置函数无法使用。 - rojomoke
3个回答

159

`` 被称为命令替换符,相当于 $() (括号),而你正在使用的是 ${} (花括号)。

因此,所有这些表达式都是相等的,并且意思是“解释放置在内部的命令”:

joulesFinal=`echo $joules2 \* $cpu | bc`
joulesFinal=$(echo $joules2 \* $cpu | bc)
#            v                          v
#      ( instead of {                   v
#                                 ) instead of }

虽然${}表达式用于变量替换。

请注意,反引号已被弃用,而$()符合POSIX标准,因此您应该更喜欢后者。


来自man bash

命令替换允许一个命令的输出替换掉命令本身。它有两种形式:

          $(command)
   or
          `command`
同时,`` 的处理更加困难,例如无法嵌套使用。请参见下面的注释以及为什么$(...)优于...(反引号)?

4
我已经调查过了,不得不承认反引号确实与POSIX标准兼容。然而,Bash仍然已将其弃用,使用 $() 处理更好。(+1) - hek2mgl
7
bash项目中也没有发现任何“真正”的废弃,这意味着反引号将在未来的版本中被删除只是一种提示。似乎使用$()只是“首选方式”。对于造成的混淆感到抱歉 :) - hek2mgl
3
没问题,@hek2mgl,我觉得这非常有趣。我有时在这里的 SO 上读到它已经被弃用了,所以这种想法很普遍(我甚至也这样想)。但对我来说,使用 $() 而不是 `` 的最重要原因是前者可以嵌套,而后者不允许嵌套。 - fedorqui
现在我们知道了 :) .. 是的,使用$()嵌套它们并需要转义的可能性是$()的一个巨大优势! - hek2mgl
7
即使你不使用嵌套,反引号在许多控制台字体中也很容易被忽略。而$()则不太容易被忽略。 - DevSolar
3
你可以使用"``"进行嵌套,只是看起来很丑陋。"echo `echo \echo abc\\`"是可以运行的。 - Daniel Lubarov

46

在特定情况下,它们的行为略有不同:

$ echo "`echo \"test\" `"
test

$ echo "$(echo \"test\" )"
"test"

因此,反引号会默默地删除双引号。


有趣的例子。我怀疑 $() 的内容在外部字符串处理其特殊字符之前运行,而不是使用反引号的情况。如果你想使用反引号并希望引号保留,echo "\echo \"test\"`"`将起作用,因为 bash 斜杠转义字符需要被转义以使其持久化内部命令的外部字符串解析。 - Chad Skeeters
区别在于它们处理转义的方式不同。这也是不同的:"echo `$var`" 和 "echo $($var)"。 - FERcsI

4

${} 指Shell参数扩展。手册链接:https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html

字符“$”用于引入参数扩展、命令替换或算术扩展。要扩展的参数名称或符号可以被包含在花括号中,花括号是可选的,但能保护被扩展的变量不受其后紧接着的字符的影响。这些字符可能被解释为名称的一部分。

当使用花括号时,匹配的结束大括号是指未被反斜杠或引号字符串内的第一个“}”,并且它不在嵌入式算术扩展、命令替换或参数扩展中。

FULLPATH=/usr/share/X11/test.conf_d/sk-synaptics.conf
 echo ${FULLPATH##*/}
echo ${FILENAME##*.}

第一个echo将获取文件名。根据手册中的${parameter##word}部分,第二个echo将获取文件扩展名。


$(command)

`command`

请参考命令替换。

Bash通过在子shell环境中执行命令并替换命令替换为该命令的标准输出来执行扩展,删除任何尾随的换行符。

https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接