当您尝试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并打印由标签分隔的ab。如果将其写为echo 'a\tb',并使用撇号在shell命令解析级别提供引用,则将更具可读性。同样,在命令行解析之后,echo \\\\是两个反斜杠,因此echo将看到\\并输出一个反斜杠。如果要直接打印a\tb而不使用其他形式的引号,则必须说echo a\\\\tb

因此,shell有一个简单的规则-在命令行上使用两个反斜杠,以在参数单词中使用一个反斜杠。而echo有一个简单的规则-参数字中的两个反斜杠会在输出中产生一个反斜杠。

但是有一个问题...当echo执行它的功能时,反斜杠后跟t表示输出制表符,反斜杠后跟反斜杠意味着输出反斜杠...但是有很多组合并不代表任何含义。例如,后跟T的反斜杠不是有效的转义序列。在C语言中,这可能是警告或错误。但是echo命令试图更宽容。

尝试使用echo \\Techo '\T',您会发现反斜杠后跟没有定义含义的任何内容(例如,反斜杠转义符)只会使echo照原样输出两个字符。

这把我们带到了最后一种情况:如果反斜杠根本不跟任何东西怎么办?如果它是论点单词中的最后一个字符怎么办?在这种情况下,echo只会输出反斜杠。

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

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

echo
\\


会“正确地”输出单个反斜杠,并在所有级别都应用引号。

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

echo
\


会“杂乱地”输出一个反斜杠,因为echo在参数末尾发现了一个反斜杠,即使它没有被转义,它也足够慷慨地为您输出。

从这些原理中,其余示例应显而易见。

关于zsh - Zsh反斜杠疯狂吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39292220/

10-14 18:56