$(stuff)和`stuff`有什么区别?


265

有两种用于命令替换的语法:带美元括号和带反引号的命令。运行top -p $(pidof init)top -p `pidof init`给出相同的输出。这两种做同一件事的方式还是不同?


18
另请参阅:BashFAQ / 082
丹尼斯·威廉姆森

42
有一秒钟我以为这是一个jQuery问题。
大卫·默多克

结果可能取决于外壳-两者都支持。
artdanil 2011年

Answers:


359

旧式的反引号` `确实会处理反斜杠,并且嵌套有点不同。新样式$()( )命令之间的所有内容解释为命令。

echo $(uname | $(echo cat))
Linux

echo `uname | `echo cat``
bash: command substitution: line 2: syntax error: unexpected end of file
echo cat

如果嵌套的反引号被转义,则有效:

echo `uname | \`echo cat\``
Linux

反斜杠的乐趣:

echo $(echo '\\')
\\

echo `echo '\\'`
\

新样式$()适用于所有符合POSIX的外壳。
正如mouviciel指出的那样,` `旧式壳可能需要旧式。

除了技术角度之外,旧样式` `还具有视觉上的缺点:

  • 很难注意到: I like $(program) better than `program`
  • 容易与单引号混淆: '`'`''`''`'`''`'
  • 键入不太容易(甚至可能不在键盘的标准布局上)

(SE ` `出于自己的目的使用,编写此答案很痛苦:)


10
我想补充的唯一的事情,就是我所说的“(”的括号,而不是一个支架(这是“[”)
肯德尔黑尔姆施泰特Gelner

@Kendall:我一直认为'{'是那些年的左括号……
SamB 2011年

5
@Sam:{ }通常被称为“大括号”或“括号” en.wikipedia.org/wiki/Braces_(punctuation)#Braces
约恩休乌-罗德

2
我还将“ {”称为花括号。虽然看起来很奇怪,但是如果您将其他内容称为方括号,则需要添加“ curly”限定符...我想这仅仅是因为它们实际上是卷曲的。
Kendall Helmstetter Gelner 2011年

1
@slim我在美国/英国键盘上不知道,但是在西班牙键盘上`是一个死键,因此我必须输入两次反引号(通常我什至忘记了我可以做的事)或反引号然后加空格,这是一个疼痛。
Darkhogg 2014年

41

我观察到的明显区别是,您不能嵌套反引号,而可以嵌套$()。也许两者都是出于遗留原因而存在。同样,.source命令是同义词。


10
一些伯恩派生的贝壳无法识别source。短跑是一个例子。
丹尼斯·威廉姆森

14
这不是真的。您可以将反引号嵌套到任何级别,但更加痛苦。请注意这两个$(...)`...`是标准的(后者被否决),同时.是标准,但不是source
斯特凡Chazelas

3
更正,仅(t)csh它们不能嵌套。(t)csh虽然不支持$(...)。他们确实支持source.但不支持)。
斯特凡Chazelas

28

$()不适用于旧的Bourne外壳。但它已经多年,因为我老Bourne shell的工作几十年。


早在1970年代和1980年代初期,对吗?
克里斯托弗

6

另一个要注意的是,$()与使用反引号相比,它将使用更多的系统资源,但速度稍快一些。

在“ 掌握Unix shell脚本”中,Randal K. Michael在名为“逐行处理文件的24种方法”的一章中进行了测试。


2
这个说法是胡说八道。没有理由为什么它应该更快,因为它只是为解析器使用了不同的符号。
schily

@schily:也许,我只引用这本书,您可以阅读以获取更多详细信息。
cuonglm 2015年

3
我倾向于同意@schily ...为什么需要更多资源?
2016年

2
@Wildcard,我想这是因为$()使您的脚本比使用的脚本大一个字节`(假设您不嵌套它们并且在其中不使用反斜杠)。至于哪一个解析起来更快,这在外壳之间会有所不同,并且与创建命令所需的创建管道和分叉过程的成本相比,可以忽略不计。
斯特凡Chazelas

5

要添加其他人在此处所说的内容,您可以使用反引号来模拟内联注释:

echo foo `# I'm a comment!` bar

输出为:foo bar

有关更多信息,请参见以下内容:https : //stackoverflow.com/a/12797512(另请注意该帖子下方的评论。)


1

$()语法不适用于旧的bourne shell。
使用更新的Shell ` `$()并且等效,但是$()当您需要嵌套多个命令时,使用起来更加方便。

例如 :

echo $(basename $(dirname $(dirname /var/adm/sw/save )))

比:更容易键入和调试:

echo `basename \`dirname \\\`dirname /var/adm/sw/save \\\`\``

1
尽管$()看起来不错,但是实现相关的解析器很麻烦,因为它需要双重递归解析器。
schily

6
@schily另一方面,如果没有良好的解析器,它将是一个shell。
伊曼纽尔

1
问题在于,在调用解析器之前,您需要知道字符串的结尾。对于反引号,这是相对简单的,但是对于括号来说,很难做到这一点,因为它们在外壳中用于各种目的。因此,您需要两次解析器并且使用Bourne Shell中不存在的方式。
schily
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.