slm*_*slm 141 shell scripting bash zsh shell-script
我在 Unix 和 Linux 以及其他使用短语“反引号已被弃用”的站点上多次看到此评论,这与 Bash 和 Zsh 等 shell 相关。
这个说法是真的还是假的?
slm*_*slm 144
“弃用”有两种不同的含义。
被弃用:(主要是软件功能)可用但被视为过时和最好避免,通常是由于已被取代。
——新牛津美式词典
根据这个定义,不推荐使用反引号。
弃用状态也可能表示该功能将在未来被删除。
—维基百科
根据这个定义,反引号不被弃用。
引用有关 Shell 命令语言的开放组规范,特别是第2.6.3节命令替换,可以看出,就规范而言,仍然支持两种形式的命令替换,反引号 ( `..cmd..`) 或美元括号 ( $(..cmd..))。
命令替换允许将命令的输出替换为命令名称本身。当命令被如下包围时,将发生命令替换:
Run Code Online (Sandbox Code Playgroud)$(command)或(反引号版本):
Run Code Online (Sandbox Code Playgroud)`command`shell 应通过在子 shell 环境中执行命令来扩展命令替换(请参阅 Shell 执行环境)并将命令替换(命令文本加上封闭
$()或反引号)替换为命令的标准输出,删除一个或多个序列<newline> 替换末尾的字符。输出结束前嵌入的 <newline> 字符不得删除;但是,它们可能会被视为字段分隔符并在字段拆分期间被消除,具体取决于 IFS 的值和有效的引用。如果输出包含任何空字节,则行为未指定。在命令替换的反引号样式中,<backslash>应保留其字面含义,除非后面跟着: '$'、'
`' 或<backslash>。匹配反引号的搜索应由第一个未加引号的非转义反引号满足;在此搜索过程中,如果在 shell 注释、here-document、$(command)表单的嵌入命令替换或带引号的字符串中遇到非转义反引号,则会出现未定义的结果。在 "`...`" 序列内开始但不结束的单引号或双引号字符串会产生未定义的结果。对于
$(command)表单,左括号后面到匹配右括号的所有字符构成命令。任何有效的 shell 脚本都可用于命令,除了仅由产生未指定结果的重定向组成的脚本。
因为大多数用例应该使用美元括号形式而不是反引号。(在上述第一种意义上已弃用。)许多最负盛名的网站(包括 U&L)也经常自始至终都声明这一点,因此这是合理的建议。这个建议不应该与一些不存在的计划相混淆,即从 shell 中删除对反引号的支持。
BashFAQ #082 - 为什么 $(...) 优于 `...`(反引号)?
`...`是最古老的非 POSIX 兼容的 bourne-shell 所需的遗留语法。总是喜欢这种$(...)语法有几个原因:...
Bash Hackers Wiki - 过时和不推荐使用的语法
这是命令替换的较旧的 Bourne 兼容形式。无论是
`COMMANDS`和$(COMMANDS)语法由POSIX规定,但后者大大首选,尽管前者是可惜还是在脚本中非常普遍。新式命令替换被每个现代 shell(以及一些)广泛实现。使用反引号的唯一原因是为了与真正的 Bourne shell(如传家宝)兼容。反引号命令替换在嵌套时需要特殊转义,并且在野外发现的示例经常被不正确地引用。请参阅: 为什么 $(...) 优于 `...`(反引号)?.
由于这些不一致的行为,对于嵌套命令替换或尝试嵌入复杂脚本的新应用程序,不建议使用反引号的各种命令替换。
注意:第三个摘录(以上)继续展示了几种情况,其中反引号根本不起作用,但较新的美元括号方法可以,从以下段落开始:
此外,反引号语法对嵌入命令的内容有历史限制。虽然较新的“$()”表单可以处理任何类型的有效嵌入脚本,但反引号形式无法处理一些包含反引号的有效脚本。
如果您继续阅读该部分,则会突出显示失败,显示它们如何使用反引号失败,但请使用较新的美元括号表示法。
因此,您最好使用美元括号而不是反引号,但实际上您并没有使用技术上“弃用”的东西,如“这将在某个计划点完全停止工作”。
阅读完所有这些后,您应该知道强烈建议您使用美元括号,除非您特别需要与真正的原始非 POSIX Bourne shell 兼容。
ken*_*orb 16
它没有被弃用,但反引号 ( `...`) 是最古老的非 POSIX 兼容的 bourne-shell 所需的遗留语法,并且$(...)是 POSIX 并且由于以下几个原因更受欢迎:
\反引号内的反斜杠 ( ) 以不明显的方式处理:
$ echo "`echo \\a`" "$(echo \\a)"
a \a
$ echo "`echo \\\\a`" "$(echo \\\\a)"
\a \\a
# Note that this is true for *single quotes* too!
$ foo=`echo '\\'`; bar=$(echo '\\'); echo "foo is $foo, bar is $bar"
foo is \, bar is \\
Run Code Online (Sandbox Code Playgroud)在里面嵌套引用$()要方便得多:
echo "x is $(sed ... <<<"$y")"
Run Code Online (Sandbox Code Playgroud)
代替:
echo "x is `sed ... <<<\"$y\"`"
Run Code Online (Sandbox Code Playgroud)
或者写一些类似的东西:
IPs_inna_string=`awk "/\`cat /etc/myname\`/"'{print $1}' /etc/hosts`
Run Code Online (Sandbox Code Playgroud)
因为$()使用全新的上下文来引用
这是不可移植的,因为 Bourne 和 Korn shell 需要这些反斜杠,而 Bash 和 dash 不需要。
嵌套命令替换的语法更简单:
x=$(grep "$(dirname "$path")" file)
Run Code Online (Sandbox Code Playgroud)
比:
x=`grep "\`dirname \"$path\"\`" file`
Run Code Online (Sandbox Code Playgroud)
因为$()强制使用全新的引用上下文,所以每个命令替换都受到保护并且可以单独处理,而无需特别关注引用和转义。当使用反引号时,它在两个及以上级别后变得越来越难看。
再举几个例子:
echo `echo `ls`` # INCORRECT
echo `echo \`ls\`` # CORRECT
echo $(echo $(ls)) # CORRECT
Run Code Online (Sandbox Code Playgroud)它解决了使用反引号时行为不一致的问题:
echo '\$x' 产出 \$xecho `echo '\$x'` 产出 $xecho $(echo '\$x') 产出 \$x反引号语法对嵌入命令的内容有历史限制,不能处理一些包含反引号的有效脚本,而较新的$()形式可以处理任何类型的有效嵌入脚本。
例如,这些在其他方面有效的嵌入脚本在左侧列中不起作用,但在右侧IEEE 中起作用:
echo ` echo $(
cat <<\eof cat <<\eof
a here-doc with ` a here-doc with )
eof eof
` )
echo ` echo $(
echo abc # a comment with ` echo abc # a comment with )
` )
echo ` echo $(
echo '`' echo ')'
` )
Run Code Online (Sandbox Code Playgroud)因此$-prefixed命令替换的语法应该是首选方法,因为它视觉清晰,语法清晰(提高人机可读性),可嵌套直观,内部解析分离,也更一致(与从双引号内解析的所有其他扩展),其中反引号是唯一的例外,并且`字符在相邻时很容易伪装,"使其更难以阅读,尤其是使用小字体或不寻常的字体时。
来源:为什么$(...)优先于`...`(反引号)?在 BashFAQ
也可以看看: