引用删除是在POSIX shell中命令替换后发生的吗?

时间:2016-08-03 05:17:49

标签: shell posix

的POSIX shell标准

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 '"')#"
>

我不理解什么?

阅读答案/评论后添加:

从每个人的意见来看,引用的考虑发生在解析的最开始,例如,以确定命令是否是可接受的"。那么为什么标准还要强调,引用删除是在过程的后期执行的?

1 个答案:

答案 0 :(得分:1)

  

"然后外部命令变为echo "#"并且是平衡的"

那不是平衡的'因为第一个双引号计数。如果引号在命令行中不受阻碍,则它们仅作为引号有意义。

要验证,请查看以下内容:

$ echo $(echo '"')#
"#

这是平衡的,因为shell确实认为"只是另一个角色。

相比之下,这是不平衡的,因为它只有一个shell活动"

$ echo $(echo '"')#"
> 

类似的例子1

这里我们展示相同的东西,但使用参数扩展而不是命令替换

$ q='"'; echo $q
"

一旦shell将"替换为$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 standard

  

用单引号括起字符('')应保留   单引号中每个字符的字面值

换句话说,一旦双引号出现在单引号内,它就没有特殊的权力:它只是另一个字符。

该标准还提到了转义和双引号作为保留"字面值的方法"一个角色。

实际后果

刚接触shell的人通常希望将命令存储在变量中,如上面的cmd='ls "file"'示例所示。但是,因为引号和其他shell-active字符一旦存储在变量中就不再是shell活动的,复杂的情况总是会失败。这导致了一篇经典论文:

"I'm trying to put a command in a variable, but the complex cases always fail!"