当你尝试echo一堆反斜杠时,Zsh似乎做了一些奇怪的反斜杠.我似乎无法找到一个非常明确的模式.这种疯狂的原因是什么?当然,如果我真的想要正确使用反斜杠,那么我会使用正确的引用等,但为什么会发生这种情况呢?
这是一个显示相同的小例子:
$ echo \\
\
$ echo \\ \\
\ \
$ echo \\ \\ \\
\ \ \
$ echo \\ \\ \\ \\
\ \ \ \
$ echo \\\\ \\ \\
\ \ \
$ echo \\\\\\ \\
\\ \
$ echo \\\\\\\\
\\
Run Code Online (Sandbox Code Playgroud)
我最初在不久前独立发现了这个,但Zach Riggle的这条推文提醒了它.
小智 5
在第一步中,echo命令并不特殊.命令行由与正在执行的命令无关的规则解析.此步骤的总体效果是将命令从一系列字符转换为一系列字符.
要了解此示例,您需要了解的两个常规解析规则是:空格字符分隔单词,反斜杠字符转义特殊字符,包括自身.
所以命令echo \\ 变成了2个单词的列表:
echo
\
Run Code Online (Sandbox Code Playgroud)
第一个反斜杠转义第二个,导致第二个单词中出现一个反斜杠.
echo \\ \\ \\ \\
Run Code Online (Sandbox Code Playgroud)
成为这个单词列表:
echo
\
\
\
\
Run Code Online (Sandbox Code Playgroud)
现在命令行解析完成.只有现在shell才会查找由第一个单词命名的命令.到目前为止,命令echo一直无关紧要.如果您说过cat \\ \\ \\ \\,将使用4个参数字调用cat,每个参数字包含一个反斜杠.
通常,当你运行时,echo你将获得shell builtin命令.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-command-parsing级别提供引用,那么它将更具可读性.同样echo \\\\是命令行解析后的两个反斜杠,因此echo看到\\并输出一个反斜杠.如果你想在a\tb不使用其他形式的引用的情况下进行字面打印,那么你必须说echo a\\\\tb.
所以shell有一个简单的规则 - 在命令行上有两个反斜杠,在参数字中产生一个反斜杠.而echo有一个简单的规则 - 参数字中的两个反斜杠在输出中产生一个反斜杠.
但是有一个问题......当echo做它的事情时,反斜杠后面的t意思是输出一个标签,反斜杠后面跟一个反斜杠意味着输出一个反斜杠...但是有很多组合并不意味着什么.T例如,反斜杠后跟不是有效的转义序列.在C中,这将是一个警告或错误.但是echo命令试图更宽容.
尝试echo \\T或者echo '\T'你会发现反斜杠后跟任何没有定义意义的反斜杠转义只会导致echo按原样输出两个字符.
这将我们带到最后一个案例:如果反斜杠没有任何后续内容怎么办?如果它是参数词中的最后一个字符怎么办?在这种情况下,echo只输出反斜杠.
总而言之,参数字中的两个反斜杠会在输出中产生一个反斜杠.但是参数字中的一个反斜杠也会导致输出中出现一个反斜杠,如果它是单词中的最后一个字符,或者反斜杠与下一个字符一起形成有效的转义序列.
命令行echo \\\\因此成为单词列表
echo
\\
Run Code Online (Sandbox Code Playgroud)
它会"正确地"输出一个反斜杠,并在所有级别应用引用.
命令行echo \\成为单词列表
echo
\
Run Code Online (Sandbox Code Playgroud)
它输出一个反斜杠"乱七八糟",因为echo在参数结束时发现了一个杂散的反斜杠,并且足够慷慨地为你输出它,即使它没有被转义.
其余的例子应该从这些原则中清楚.