当您尝试echo
一堆反斜杠时,Zsh似乎做了一些奇怪的反斜杠。我似乎无法为此找到一个非常清晰的模式。有什么疯狂的理由吗?当然,如果我实际上想正确使用反斜杠,那么我将使用正确的引号等,但是为什么这首先发生呢?
这是一个显示相同内容的小示例:
$ echo \\
\
$ echo \\ \\
\ \
$ echo \\ \\ \\
\ \ \
$ echo \\ \\ \\ \\
\ \ \ \
$ echo \\\\ \\ \\
\ \ \
$ echo \\\\\\ \\
\\ \
$ echo \\\\\\\\
\\
我最初是在一段时间前独立发现的,但是Zach Riggle的this tweet提醒了我这一点。
最佳答案
第一步,echo命令并不特殊。命令行由与正在执行的命令无关的规则解析。此步骤的总体效果是将命令从一系列字符转换为一系列单词。
您需要了解的两个常规解析规则是:空格字符分隔单词,反斜杠字符转义特殊字符,包括其自身。
因此,命令echo \\
成为2个单词的列表:
echo
\
第一个反斜杠转义第二个反斜杠,导致第二个单词中出现一个反斜杠。
echo \\ \\ \\ \\
变成以下单词列表:
echo
\
\
\
\
现在,命令行解析完成。直到现在,shell才会查找第一个单词命名的命令。到现在为止,该命令为
echo
的事实一直没有关系。如果您说cat \\ \\ \\ \\
,则cat将被4个参数词调用,每个参数词包含一个反斜杠。通常,当您运行
echo
时,将获得shell内置命令。 zsh内置回显具有可配置的行为。我喜欢使用setopt BSD_ECHO
选择BSD样式的回显行为,但是从示例输出中,您似乎处于默认模式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在参数末尾发现了一个反斜杠,即使它没有被转义,它也足够慷慨地为您输出。
从这些原理中,其余示例应显而易见。
关于zsh - Zsh反斜杠疯狂吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39292220/