在bash中
$ va='\\abc'
$ echo $va
\\abc
在赋值中va='\\abc'
,单引号保留了值中的两个反斜杠va
。
在echo命令中,bash首先对参数扩展(expand it to ),然后对参数扩展的结果进行引号去除,echo $va
是否正确?删除引号会删除反斜杠和引号,但为什么两个反斜杠仍然保留?我预计结果是.用于比较$va
\\abc
\abc
$ echo \\abc
\abc
我错过了 bash 手册中的某些内容吗?我很感激有人能指出我错过了什么。
谢谢。
答案1
从更简单的比较开始:
$ echo '\\abc'
\\abc
$ echo \\abc
\abc
在第一个命令中,撇号不会成为参数的一部分,因为echo
它们已用于引用。里面的所有字符,包括两个反斜杠,都被传递到echo
.
在第二个命令中,第一个反斜杠引用第二个反斜杠。用于引用的内容不会成为 的论证的一部分echo
。另一个被传递给echo
, 以及 the abc
(未引用,但这并不重要,因为它们不是元字符)。
现在我们准备讨论您的命令序列
$ va='\\abc'
$ echo $va
\\abc
当执行赋值命令时,撇号会引用它们之间的所有内容。撇号不会成为分配值的一部分,但其他所有内容都会成为分配值的一部分,包括两个反斜杠。
在echo
命令中,没有引号字符。va
检索的值并将其插入到参数列表中。现在有一个包含 2 个反斜杠的参数,但它们不能用作引用字符,因为我们查找引用字符的解析阶段是在变量扩展之前完成的。
变量扩展不同于宏扩展。生成的一系列参数不会反馈到完整的命令行解析器。完成了一些后处理(分词和通配符),但没有第二次删除引号和变量扩展。
当您想要构建参数列表并将整个内容重新解析为具有所有可用 shell 功能的新命令行时,您可以使用eval
.这通常是一个坏主意,因为“所有 shell 功能”很多,如果不小心,可能会发生不好的事情。
$ va='\\abc'
$ eval echo $va
\abc
完美,对吧?
$ va='\\abc;rm -rf $important_database'
$ eval echo $va
\abc
^C^C^C ARGH!
当您发现自己想要在 shell 变量的值中使用 shell 引用语法时,请尝试考虑一种不同的方法来解决您的问题。
答案2
我错过了 bash 手册中的某些内容吗?
是的。来自手册:
在前面的扩展之后,所有未加引号且不是由上述扩展之一产生的字符 '
\
'、''
' 和 ' ' 的出现都将被删除。"
这里的“前面的扩展”和“上面的扩展”是指参数(变量)扩展、命令替换等。
答案3
答案很简单,一行:
echo $va
不包含需要删除的引号。
这就是 40 多年来 shell 的定义。请注意,Bourne Shell 于 1976 年首次出现在 AT&T 内部。
顺便说一句:“引用”在这方面意味着 20 世纪 70 年代第 8 位打开的字符。所以这是 shell 内部引用的形式。
由于 Bourne Shell 已被重新设计以支持 8 位字符,因此在 20 世纪 80 年代中期,这种内部引用形式已被内部字符串中任何引用字符之前的反斜杠所取代。
如今,Bourne Shell 的工作方式如下:
用单引号编写的字符串将替换为反斜杠形式。例如,这意味着 'abc' 被替换为 \a\b\c
带有明确类型反斜杠的字符串保留在内部。
带双引号的字符串保留其双引号,因此“abc”在内部保留为“abc”
在进行参数扩展时,shell 将所有类型的带引号的字符串(参见上面的三种形式)替换为在任何字符之前带有单反斜杠的形式,这就是在执行“引号删除”时删除的内容。
顺便说一句:变量扩展:
abc=123
完成了
command "$abc"
结果是
command \1\2\3
在完成报价删除之前。
command $abc
结果是
command 123
在完成报价删除之前。