在shell脚本中使用$()而不是反引号的好处是什么?
有两种方法可以捕获bash
中命令行的输出:
-
传统的Bourne shell反引号
``
:var=`command`
-
$()
语法(据我所知是Bash具体)var=$(command)
与反引号相比,使用第二个语法有什么好处? 还是两个完全等同于100%?
最主要的是能够嵌套他们,命令内的命令,而不会失去理智,试图找出是否某种forms的逃逸将反作用。
一个例子,虽然有点人为的做法:
deps=$(find /dir -name $(ls -1tr 201112[0-9][0-9]*.txt | tail -1l) -print)
这将给你一个在/dir
目录树中所有与2011年12月(a)最早的date文本文件具有相同名称的文件列表。
另一个例子是像获取父目录的名称(不是完整path):
pax> cd /home/pax/xyzzy/plugh pax> parent=$(basename $(dirname $PWD)) pax> echo $parent xyzzy
(a)现在具体的命令可能实际上不起作用,我还没有testing过这个function。 所以,如果你为此投下我的意见,你已经看不到这个意图了:-)这只是一个说明你如何嵌套,而不是一个无bug的生产就绪片段。
假设你想find与gcc
安装位置相对应的lib目录。 你有一个select:
libdir=$(dirname $(dirname $(which gcc)))/lib libdir=`dirname \`dirname \\\`which gcc\\\`\``/lib
第一个比第二个更容易 – 使用第一个。
从男人bash:
$(command) or `command` Bash performs the expansion by executing command and replacing the com- mand substitution with the standard output of the command, with any trailing newlines deleted. Embedded newlines are not deleted, but they may be removed during word splitting. The command substitution $(cat file) can be replaced by the equivalent but faster $(< file). When the old-style backquote form of substitution is used, backslash retains its literal meaning except when followed by $, `, or \. The first backquote not preceded by a backslash terminates the command sub- stitution. When using the $(command) form, all characters between the parentheses make up the command; none are treated specially.
反引号( `...`
)是只有最老的非POSIX兼容的bourne-shells才需要的传统语法,而$(...)
是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 shell需要这些反斜杠,而Bash和Dash则不需要。
-
嵌套命令replace的语法比较简单:
x=$(grep "$(dirname "$path")" file)
比:
x=`grep "\`dirname \"$path\"\`" file`
因为
$()
强制引用一个全新的上下文,所以每个命令replace都是受保护的,并且可以自行处理,而不用引用和转义。 当使用反引号时,在两个或更多级别之后会变得更加丑陋和丑陋。几个例子:
echo `echo `ls`` # INCORRECT echo `echo \`ls\`` # CORRECT echo $(echo $(ls)) # CORRECT
-
它解决了使用反引号时行为不一致的问题:
-
echo '\$x'
输出\$x
-
echo `echo '\$x'`
输出$x
-
echo $(echo '\$x')
outputs\$x
-
-
反引号语法对embedded式命令的内容具有历史限制,不能处理一些包含反引号的有效脚本,而较新的
$()
表单可以处理任何种类的有效embedded脚本。例如,这些其他有效的embedded式脚本不能在左列中工作,但是可以在正确的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 命令replace的语法应该是首选的方法,因为它清晰的语法清晰(提高了人机可读性),它是可嵌套和直观的,它的内部parsing是分离的,并且也是更一致的与所有其他扩展在双引号内parsing),反引号是唯一的例外, `
字符很容易被伪装在邻近"
,这使得阅读变得更加困难,特别是对于小字体或不寻常的字体。
资料来源: 为什么$(...)
优先于`...`
(反引号)? 在BashFAQ
也可以看看:
- POSIX标准部分“2.6.3命令replace”
- 包含$()语法的POSIX基本原理
- 命令replace
- bash-hacker:命令replace
除了其他答案之外,
$(...)
在视觉上比从视觉上更好
`...`
反引号看起来太像撇号; 这取决于你使用的字体。
(而且,正如我刚才注意到的,反引用代码很难进入内联代码示例。)
$()
允许嵌套。
out=$(echo today is $(date))
我觉得反驳是不允许的。
这是POSIX标准,它定义了$(command)
forms的命令replace。 目前使用的大多数shell都是POSIX兼容的,并且支持这种优先的forms而不是古老的反引号。 Shell语言文档的命令replace部分(2.6.3)描述了这一点:
命令replace允许将命令的输出replace为命令名称本身。 当命令被包含时,命令replace将发生如下:
$( command )
或(反引号):
` command `
shell将通过在子shell环境中执行命令来扩展命令replace(参见Shell执行环境 ),并用命令的标准输出replace命令replace(command的文本加上括号“$()”或反引号),移除replace结尾处的一个或多个
<newline>
字符的序列。 在输出结束之前embedded的<newline>
字符不得被删除; 然而,它们可能会被视为字段分隔符,并在字段拆分期间被删除,具体取决于IFS的价值和引用是否有效。 如果输出包含任何空字节,则行为是未指定的。在反引用的命令replace样式中,
<backslash>
应保留其字面含义,除非后面跟着:'$
','`
'或<backslash>
。 search匹配的反引号应该由第一个不带引号的非反引号来满足; 在search期间,如果在shell注释,here-document,$( command )表单或带引号的string的embedded式命令replace中遇到未转义的反引号,则会发生未定义的结果。 在“`...`
”序列中开始但不结束的单引号或双引号string会产生未定义的结果。使用$( command )forms,左括号后面的所有字符构成命令 。 任何有效的shell脚本都可以用于命令 ,除了仅由redirect组成的脚本以外,它们会产生未指定的结果。
命令replace的结果不得进行进一步的代字符扩展,参数扩展,命令replace或算术扩展。 如果在双引号内发生命令replace,则不应对replace结果执行字段拆分和path名扩展。
命令replace可以嵌套。 要指定反向引用版本中的嵌套,应用程序应在内部反引号之前加上
<backslash>
字符; 例如:
\` command \`
shell命令语言的语法对于以“
$((
”)开头的扩展是不明确的,它可以引入一个算术扩展或者以subshell开头的命令replace。算术扩展有优先权,也就是说,它可以将扩展parsing为一个算术扩展,只有当它确定不能将扩展parsing为一个算术扩展时,才会将扩展parsing为一个命令replace,在执行这个确定时,shell不需要评估嵌套扩展。在没有确定不能将扩展parsing为算术扩展的情况下,shell将扩展视为一个不完整的算术扩展并报告一个语法错误,一个合适的应用程序应确保它将“$(
”和“(
'换成两个令牌(换句话说,用空格隔开),以一个子shell开始的命令replace。例如,一个通讯 并且包含一个子shell的replace可以写成:
$( ( command ) )
这是一个遗留问题,但是我想出了一个完美有效的例子$(...)
。
我正在使用远程桌面来运行cygwin的窗口,并想迭代一个命令的结果。 可悲的是,无论是远程桌面还是cygwin本身,反引号字符都无法进入。
假设美元符号和圆括号可以更容易地input这种奇怪的设置是理智的。