命令替换:反引号还是美元符号/括号包含?

187

在bash中,最常用的命令替换方式是什么?

我一直都是这样做的:

echo "Hello, `whoami`."

但是最近,我经常看到它被写成这样:
echo "Hello, $(whoami)."

什么是首选语法?为什么?或者它们基本上是可以互换的吗?

我倾向于使用第一种,只是因为我的文本编辑器似乎知道它是什么,并且可以适当地进行语法高亮。

我在这里读到转义字符在每种情况下都有点不同,但我不清楚哪种行为更可取,或者它只是取决于情况。

附带问题:在一个脚本中同时使用两种形式是否是不好的实践,例如在嵌套命令替换时?


1
顺便提一下:这个例子不起作用 :) 你应该使用:echo "Hello, $(whoami)"'!'(因为使用了感叹号) - rmuller
@rmuller,这就是我没有测试例子的后果。改成了句号。 :) - Dagg Nabbit
值得注意的是,当使用set -e时,反引号中的失败命令将导致脚本失败并退出,但$()中的失败命令不会。 - Suchipi
3个回答

195
这里有几个问题/问题,所以我会重复海报文本的每个部分,并跟随我的回答。

什么是首选语法,为什么?还是它们几乎可以互换使用吗?

我认为$(some_command)形式优于`some_command`形式。第二种形式使用一对反引号("`"字符,也称为反引号和重音符号),是历史上的做法。第一种形式使用美元符号和括号,是较新的POSIX形式,这意味着它可能是更标准的做法。因此,我认为这意味着它更有可能正确地在不同的shell和不同的*nix实现中工作。

另一个给出偏爱第一(POSIX)形式的原因是,它更容易阅读,特别是当命令替换嵌套时。此外,在反引号形式中,反引号字符必须在嵌套(内部)命令替换中进行反斜杠转义。

使用POSIX形式,您不需要这样做。

至于它们是否可以互换使用,那么,通常情况下,除了您提到的转义字符的异常情况外,它们是可以互换使用的。但是,我不知道并且不能说所有现代shell和所有现代*nix是否支持两种形式。我怀疑他们这样做,特别是旧壳/旧*nix。如果我是您,我不会依赖互换性,而是先在计划在其中运行完成脚本的任何shell / * nix实现上运行每种表单的一些快速简单测试。

我倾向于首选第一种,仅仅因为我的文本编辑器似乎知道它是什么,并适当地进行语法高亮。

很遗憾,您的编辑器似乎不支持POSIX形式;也许您应该检查一下是否有更新的编辑器支持以POSIX方式进行操作。也许是个冒险,但谁知道呢?或者,您甚至可以考虑尝试不同的编辑器。

GGG,您正在使用哪个文本编辑器?

我在这里读到转义字符在每种情况下的行为略有不同,但我不清楚哪种行为更可取,还是只取决于情况。

我认为这取决于您想要实现什么目标; 换句话说,您是否与命令替换一起使用转义字符。

附加问题:在一个脚本中同时使用这两种形式是否是不良实践,例如嵌套命令替换时?

嗯,它可能会使脚本稍微容易阅读(从排版角度来看),但难以理解! 读取您的脚本的人(或六个月后的您!)可能会想知道为什么不只坚持一种形式 - 除非您在注释中写明了为什么这样做。此外,在一个脚本中混合使用两种形式会使该脚本不太可能被移植:为了使脚本正常工作,执行它的 shell 必须支持 BOTH 形式,而不仅仅是其中一种形式。

为了使shell脚本易于理解,我个人倾向于在任何一个脚本中坚持一种形式,除非有很好的技术原因做其他事情。此外,我更喜欢 POSIX 形式而不是旧形式; 再次,除非有很好的技术原因做其他事情。

关于命令替换的更多信息以及执行它的两种不同形式,请参阅 Robbins 和 Beebe 的 O'Reilly 书籍“Classic Shell Scripting”,第二版中的命令替换部分。在该部分中,作者指出,对于所有新开发,“建议使用 POSIX 形式”。我对这本书没有经济利益; 它只是我拥有(并且喜欢)的有关 shell 脚本编写的书籍,尽管它更适用于中级或高级 shell 脚本编写,而不是用于开始 shell 脚本编写。

-B.


6
哇,我被这个答案的彻底性震撼了。我通常会使用gedit进行日常事务;它会将反引号之间的内容加粗显示。 - Dagg Nabbit
13
整体答案不错 - 但最好使用括号。但请记住,反引号 POSIX 标准的一部分。答案格式错误的表述错误地暗示它不是标准的一部分。 - zaTricky
3
我对“第一种形式,使用美元符号和括号,是新的 POSIX 形式”的声明来源感到好奇,因此这里提供了相关 POSIX 规范 - 7heo.tk

54

你可以从Bash手册中了解它们之间的区别。 在大多数情况下,它们是可以交换使用的。


需要注意的一点是,您应该转义反引号(backquote)来嵌套命令:

$ echo $(echo hello $(echo word))
hello word    

$ echo `echo hello \`echo word\``
hello word


12
当你在反引号中使用三级嵌套时,情况会变得非常混乱。最好还是使用$()的格式。 - glenn jackman
4
因此,我经常使用反引号表示第一层级,使用 $() 表示更深层次的嵌套。 - Kevin
32
@glennjackman,你不想让你的命令长度指数增加吗?“echo ` echo \ echo \\\\ echo \\\\ whoami \\\\\\\\ \\ \\ ``(在编辑Markdown时同样是一场噩梦)。 - ceyko
11
为了经历了 Markdown 的痛苦而点赞。 :-) - cdunn2001
对我有用!谢谢! - Bevilaqua
显示剩余2条评论

12

反引号符号(backticks)与古老的shell兼容,所以需要可移植性脚本(例如GNU autoconf片段)应该优先使用它们。

$()形式对于眼睛来说更加容易阅读,特别是在几个转义级别之后。


在经过几个级别的转义后,如何转义第二级反引号?\`?我想我从来没有深入到那个程度;) - Dagg Nabbit
9
关键是要意识到反斜杠本身必须被转义:echo \`echo \\`echo \\\\`pwd\\\\`\\`\ - phs

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