在POSIX shell中的命令替换之后是否会删除引号



的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活动字符,所以复杂的情况总是会失败。这引出了一篇经典文章:

"我试图将命令放入变量中,但复杂的情况总是失败!"

最新更新