* sh外壳中的反引号(即“ cmd”)是否已被弃用?


118

我在Unix&Linux以及其他使用“反引号已被弃用”的网站上(例如Bash和Zsh)多次见过此评论。

这句话是对还是错?


请参阅为什么不在Shell脚本中使用反引号帮助我cd访问目录,以获取有关为什么使用$(...)符号比嵌套反引号更容易使用的示例。
Jonathan Leffler 2014年


1
至少有一个Unix AIX记录了反引号已过时。“尽管ksh接受了反引号语法,但X / Open Portability Guide Issue 4和POSIX标准认为它已作废。这些标准建议可移植应用程序使用$(command)语法。” ibm.com/support/knowledgecenter/ssw_aix_71/com.ibm.aix.osdevice/…–
Christopher,

我在Mac 10.10上的“ GNU bash版本3.2.57(1)-发行版(x86_64-apple-darwin14)”中有明确的区别:matchingLines=$( grep -n '\$-PARAMETER' ... | ... )有效,matchingLines= backtick the same stuff backtick不起作用-似乎在反斜杠美元中失去了反斜杠。(这不是我的剧本...)
denis

Answers:


126

“已弃用”有两种不同的含义。

不推荐使用:(主要是软件功能)可以使用,但通常已被取代,因此被认为已过时且最好避免。

—新牛津美国词典

通过此定义不建议使用反引号。

过时的状态也可能表示该功能将来会被删除。

维基百科

根据此定义,不建议使用反引号。

仍受支持:

引用壳命令语言开放组规范,特别是“ 2.6.3命令替换”部分,可以看出,在规范的范围内,仍支持两种形式的命令替换,反引号(`..cmd..`)或美元括号($(..cmd..))。

摘抄

命令替换允许替换命令名称本身来替换命令的输出。当命令包含以下内容时,应进行命令替换:

          $(command)

          or (backquoted version):

          `command`

外壳程序应通过在子外壳程序环境(请参见外壳程序执行环境)中执行命令,并用命令$()的标准输出替换命令替换项(命令文本加上后缀或反引号)来扩展命令替换,并删除一个或多个序列替换末尾的<newline>字符。在输出末尾之前嵌入的<newline>字符不得删除;但是,根据IFS的值和有效的引用,它们可以被视为字段定界符并在字段拆分期间被消除。如果输出包含任何空字节,则行为未指定。

在命令替换的加引号的样式内,<backslash>保留其字面含义,除非后面跟有'$',' \`'或<backslash>。对匹配的反引号的搜索应由第一个未引号的非转义反引号来满足;在此搜索期间,如果在外壳程序注释,此处文档,该$(command)格式的嵌入式命令替换或带引号的字符串中遇到了非转义的反引号,则会发生未定义的结果。在“ `...`”序列内开始但不结束的单引号或双引号字符串会产生未定义的结果。

使用该$(command)格式,在开括号后面到匹配的闭括号后面的所有字符构成命令。可以将任何有效的Shell脚本用于命令,但仅由重定向组成的脚本会产生未指定的结果。

那么,为什么每个人都说反引号已被弃用?

因为大多数用例应该使用美元括号形式而不是反引号。(在上面的第一个意义上已弃用。)许多最著名的站点(包括U&L)也经常在整个过程中都声明这一点,因此这是合理的建议。该建议不应与一些不存在的计划混淆,该计划从壳中删除了对反引号的支持。

注意:上面的第三段摘录继续显示了反引号根本不起作用的几种情况,但是较新的Dollar parens方法却起作用,从以下段落开始:

此外,反引号语法对嵌入式命令的内容有历史限制。虽然较新的“ $()”表单可以处理任何类型的有效嵌入式脚本,但带反引号的表单不能处理某些包含反引号的有效脚本。

如果您继续阅读该部分,则会突出显示失败,并显示使用反引号将失败的方式,但是使用较新的美元parens表示法则可以完成工作。

结论

因此,最好使用美元原价而不是反引号,但实际上并没有使用在技术上已“弃用”的东西,例如“这将在计划的某个时刻完全停止工作”。

阅读完所有这些内容后,应该强烈建议您使用美元括号,除非您特别要求与真实的原始非POSIX Bourne外壳兼容。


26
通过大部分的含义过时,我(和你)会说,反引号弃用。这主要是一个术语问题。
斯特凡Chazelas

4
@StephaneChazelas-同意!我将继续告诉ppl,它们已被弃用,但反引号尚未正式“弃用”,即它们将在不久的将来从所有Shell的代码库中主动删除。至少我不知道。
slm

3
我的解释是,仅支持反引号,因为它们在现有代码中根深蒂固,无法正式弃用。我从未听说过要在新代码中继续使用它们的争论。
chepner 2014年

3
@slm是的,我想您确实知道了-我被拉开了,没有注意到。几乎没有理由使用这些东西,除了在对子壳进行分层时可以使它更$( cmd `cmd`)干净之外$( cmd $(cmd)),它的杂乱程度也要少得多-易于阅读。我只是一直认为软件中已弃用的功能已被正式标记为上游要删除的功能-我从未听说过类似的功能。我不在乎-对坟墓没有爱。
mikeserv

3
您可能需要在POSIX标准基础上添加以下引号:由于这些不一致的行为,对于嵌套命令替换或尝试嵌入复杂脚本的新应用程序,建议不要使用反引号的命令替换。尽管这不是正式的弃用,因为基本原理部分是提供信息的内容,而不是规范性的内容,但它确实建议应避免继续使用反引号。
jw013

15

它不被弃用,但是反引号(`...`)是仅最老的非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 \\
    
  • 内部的嵌套引用$()要方便得多:

    echo "x is $(sed ... <<<"$y")"

    代替:

    echo "x is `sed ... <<<\"$y\"`"

    或写类似:

    IPs_inna_string=`awk "/\`cat /etc/myname\`/"'{print $1}' /etc/hosts`

    因为$()使用全新的上下文进行报价

    这不是便携式的,因为Bourne和Korn外壳将需要这些反斜杠,而Bash和dash则不需要。

  • 嵌套命令替换的语法更容易:

    x=$(grep "$(dirname "$path")" file)

    比:

    x=`grep "\`dirname \"$path\"\`" file`

    因为$()强制使用全新的引用上下文,所以每个命令替换都受到保护,可以单独处理,而不必特别关注引用和转义。使用反引号时,两个或以上级别后变得越来越难看。

    几个例子:

    echo `echo `ls``      # INCORRECT
    echo `echo \`ls\``    # CORRECT
    echo $(echo $(ls))    # CORRECT
    
  • 它解决了使用反引号时行为不一致的问题:

    • echo '\$x' 输出 \$x
    • echo `echo '\$x'` 输出 $x
    • echo $(echo '\$x') 输出 \$x
  • Backticks语法对嵌入式命令的内容有历史限制,不能处理某些包含反引号的有效脚本,而较新的$()格式可以处理任何类型的有效嵌入式脚本。

    例如,这些其他有效的嵌入式脚本在左栏中无效,但在右侧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 ')'
    `                              )
    

因此,$-prefixed 命令替换的语法应该是首选方法,因为它在语法上清晰明了(提高了人机可读性),可嵌套且直观,内部解析是独立的,并且更加一致(与所有其他从双引号内进行解析的扩展名),其中反引号是唯一的例外,并且`当与字符相邻时,很容易伪装字符",尤其是使用小字体或特殊字体时,字符甚至更难以阅读。

资料来源:为什么$(...)`...`(反引号)更受青睐?在BashFAQ

也可以看看:

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.