Zsh反斜杠疯狂?

Zsh反斜杠疯狂?,zsh,backslash,Zsh,Backslash,当你试图回显一堆反斜杠时,Zsh似乎会做一些奇怪的反斜杠。我似乎找不出一个非常清晰的模式。这种疯狂有什么原因吗?当然,如果我真的想正确地使用反斜杠,那么我会使用正确的引用等,但是为什么会发生这种情况呢 下面是一个小例子来说明这一点: $ echo \\ \ $ echo \\ \\ \ \ $ echo \\ \\ \\ \ \ \ $ echo \\ \\ \\ \\ \ \ \ \ $ echo \\\\ \\ \\ \ \ \ $ echo \\\\\\ \\ \\ \ $ echo \\

当你试图
回显一堆反斜杠时,Zsh似乎会做一些奇怪的反斜杠。我似乎找不出一个非常清晰的模式。这种疯狂有什么原因吗?当然,如果我真的想正确地使用反斜杠,那么我会使用正确的引用等,但是为什么会发生这种情况呢

下面是一个小例子来说明这一点:

$ echo \\
\
$ echo \\ \\
\ \
$ echo \\ \\ \\
\ \ \
$ echo \\ \\ \\ \\
\ \ \ \
$ echo \\\\ \\ \\
\ \ \
$ echo \\\\\\ \\
\\ \
$ echo \\\\\\\\
\\

我最初是在不久前独立发现这一点的,但扎克·里格尔让我想起了这一点

在第一步中,echo命令并不特殊。命令行由独立于正在执行的命令的规则进行解析。此步骤的总体效果是将命令从一系列字符转换为一系列单词

要理解此示例,您需要知道两个通用解析规则:空格字符分隔单词,反斜杠字符转义特殊字符,包括其本身

因此,命令
echo\\\
变成了一个包含两个单词的列表:

echo
\
第一个反斜杠转义第二个反斜杠,导致第二个单词中出现一个反斜杠

echo \\ \\ \\ \\
成为以下单词列表:

echo
\
\
\
\
现在命令行解析完成了。直到现在,shell才查找由第一个单词命名的命令。到目前为止,命令是
echo
这一事实与此无关。如果您说的是
cat\\\\\\\\\\\
,则cat将使用4个参数词调用,每个参数词都包含一个反斜杠

通常,当您运行
echo
时,您将获得shell内置命令。zsh内置echo具有可配置的行为。我喜欢使用
setopt BSD_ECHO
来选择BSD样式的ECHO行为,但是从示例输出来看,您似乎处于默认模式,即SysV样式

BSD风格的echo不做任何反斜杠处理,它只会在收到它们时打印它们

SysV echo处理反斜杠转义,如在C字符串中-
\t
变为制表符,
\r
变为回车符等。
\C
也被解释为“在不换行的情况下结束输出”

因此,如果您说
echo a\\tb
,那么shell解析将导致给echo的参数单词中出现一个反斜杠,echo将解释
a\tb
,并打印
a
b
,用一个制表符分隔。如果以
echo'a\tb'
的形式编写,使用撇号在shell命令解析级别提供引用,则更具可读性。同样地,
echo\\\\\
在命令行解析后是两个反斜杠,因此echo看到
\\\\
并输出一个反斜杠。如果您想在不使用其他形式的引用的情况下按字面意思打印
a\tb
,则必须说
echo a\\\\tb

因此,shell有一个简单的规则——在命令行上使用两个反斜杠,在参数单词中使用一个反斜杠。echo有一个简单的规则——在参数单词中加两个反斜杠,在输出中加一个反斜杠

但是有个问题。。。当echo执行其操作时,反斜杠后跟
t
表示输出选项卡,反斜杠后跟反斜杠表示输出反斜杠。。。但是有很多组合并不意味着什么。例如,后跟
T
的反斜杠不是有效的转义序列。在C语言中,这可能是一个警告或错误。但是echo命令试图更加宽容

尝试
echo\\T
echo'\T'
,您会发现反斜杠后跟任何没有定义为反斜杠转义的内容,只会导致echo按原样输出两个字符

这就引出了最后一种情况:如果反斜杠后面没有任何东西怎么办?如果它是参数单词中的最后一个字符呢?在这种情况下,echo只输出反斜杠

总之,参数单词中的两个反斜杠导致输出中的一个反斜杠。但是,如果参数单词中的一个反斜杠是单词中的最后一个字符,或者该反斜杠与下一个字符没有形成有效的转义序列,则该反斜杠也会导致输出中的一个反斜杠

命令行
echo\\\\\
因此成为单词列表

echo
\\
echo
\
输出一个反斜杠“正确”,并在所有级别应用引号

命令行
echo\\
成为单词列表

echo
\\
echo
\
它输出一个反斜杠“杂乱无章”,因为echo在参数末尾发现了一个错误的反斜杠,并且慷慨地为您输出了它,即使它没有逃逸

其余的例子应该从这些原则中清晰可见