的POSIX外壳标准
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_04
第2.6节:
command substitution (...) shall be performed
(...)
Quote removal (...) shall always be performed last.
在我看来,在命令替换后不会执行报价删除:
$ echo "#"
#
$ echo '"'
"
正如预期的那样,但是
$ echo $(echo '"')#"
>
我有什么不明白的?
阅读答案/评论后添加:
根据每个人的说法,引号的考虑发生在解析的一开始,例如,决定一个命令是否"可接受"。那么,为什么标准要强调,引号的删除是在过程的后期执行的呢??
"则外部命令变为
echo "#"
并保持平衡"
这不是"平衡的",因为第一个双引号不包含。只有当引号在命令行中不受阻碍时,引号才有意义。
为了验证,让我们看看这个:
$ echo $(echo '"')#
"#
这是平衡的,因为shell确实认为"
只是另一个字符。
相比之下,这是不平衡的,因为它有一个并且只有一个外壳活性"
:
$ echo $(echo '"')#"
>
类似示例1
这里我们展示了同样的东西,但使用参数扩展而不是命令替换:
$ q='"'; echo $q
"
一旦外壳用"
代替了$q
,人们可能会认为存在不平衡的双引号。但是,该双引号是参数扩展的结果,因此不是shell活动引号。
类似示例2
让我们考虑一个包含file
:的目录
$ ls
file
$ ls "file"
file
正如您在上面看到的,引号删除是在运行ls
之前执行的。
但是,考虑一下这个命令:
$ echo ls $(echo '"file"')
ls "file"
如您所见,ls $(echo '"file"')
扩展为ls "file"
,这是上面成功运行的命令。现在,让我们试着运行:
$ ls $(echo '"file"')
ls: cannot access '"file"': No such file or directory
正如您所看到的,shell不处理命令替换后保留的双引号。这是因为这些引号不被认为是shell活动的。因此,它们被视为普通字符,并传递给ls
,后者会抱怨目录中不存在名称以"
开头和结尾的文件。
这里也发生了同样的事情:
$ cmd='ls "file"'
$ $cmd
ls: cannot access '"file"': No such file or directory
POSIX标准
来自POSIX标准:
用单引号(")括起的字符应保留单引号中每个字符的文字值
换句话说,一旦双引号出现在单引号中,它就没有特殊的力量:它只是另一个字符。
该标准还提到转义和双引号是保留字符"文字值"的方法。
实际后果
刚接触shell的人通常希望将命令存储在变量中,如上面的cmd='ls "file"'
示例所示。但是,因为引号和其他shell活动字符一旦存储在变量中就不再是shell活动字符,所以复杂的情况总是会失败。这引出了一篇经典文章:
"我试图将命令放入变量中,但复杂的情况总是失败!"