命令替换中的Bash引用

命令替换中的Bash引用,bash,Bash,我很难理解这一点。 以下命令用于展开文件: % echo "(echo " * " )" (echo foo.txt bar.txt ) 但事实并非如此 % echo "$(echo " * " )" * 星号*不带引号。这两种情况下不都应该发生文件全球化吗?命令替换如何影响这种情况 % echo "$(echo " * " )" # --------|--------| #produces | | # echo " * " 这是一个引用的* 对于您显

我很难理解这一点。 以下命令用于展开文件:

% echo "(echo " * " )"
(echo  foo.txt bar.txt  )
但事实并非如此

% echo "$(echo " * " )"
 * 
星号*不带引号。这两种情况下不都应该发生文件全球化吗?命令替换如何影响这种情况

% echo "$(echo " * " )"
# --------|--------|
#produces |        |
#         echo " * "
这是一个引用的
*

对于您显示的外部
echo
,相同,cmd替换的输出被引用,您只看到一个
*

也就是说,
$(..)
中的内容在执行封闭命令之前进行处理


IHTH

单独查看这些命令很有帮助

% echo "(echo " * " )"
…只有一个引用上下文。在这里,
(echo
被引用,一个
*
被给出而不被引用,然后一个
被给出而被引用


这里,您正在执行一个命令替换,内部命令有自己的引用上下文。具体而言,该内部命令是:

# the inner command for the substitution is run first
echo " * "
…正如人们所期望的那样,它以
*
作为输出。值得注意的是,因为它有自己的引用上下文,所以内容开始时不带引号,只有在看到
时才会被引用

然后,执行替换;因为
$()
在引号内,所以该替换过程不会运行字符串拆分和全局扩展(如果遵循这些步骤,则会将内部命令的输出拆分为多个字,并将每个字作为全局扩展)

…因此成为

# effectively single-quoted because we already finished running expansions
# so expansions that would be allowed in double-quotes are already finished
echo ' * '

相比之下,如果您没有引用:

echo $(echo "*")
…将成为

echo *
…其行为符合您的预期


或者,反过来说

echo "$(echo *)"
…将成为类似于

echo 'foo.txt bar.txt'

如果说第二个引号中没有星号,这是不准确的。
$()
会打开一个新的引用上下文——因此,只有在打开引号时,引号才会在该场景中开始。相反,使用
()
,没有打开新的上下文。@CharlesDuffy我想这就是答案,请这样说:)我接受了,因为这给出了一个更完整的解释。问题是bash参考手册()没有详细说明任何嵌套情况。另外,尽管我听说过这种“命令替换”有自己的引用上下文“在stackoverflow中有几次,它在bash手册中奇怪地丢失了。bash遵循POSIX sh规范,
$()
就是从那里来的。如果你想要一个规范化的语言引用,那就是head的方法。请参阅中的第2.2.3节和第2.3节规则5。你是对的。我正在寻找能够解决歧义情况的语言规范。2.2.3明确规定了我想知道的内容。谢谢
echo "$(echo *)"
echo 'foo.txt bar.txt'