为什么“echo -e”命令似乎没有产生正确的输出?

yol*_*n00 21 command-line echo

在 Ubuntu 18.04 LTS 的终端中,当我写这个命令时:

echo -e "Hello\\\n"
Run Code Online (Sandbox Code Playgroud)

它给出了这个作为输出:

Hello\n
Run Code Online (Sandbox Code Playgroud)

但它应该打印,正如手册页所说:

Hello\

Run Code Online (Sandbox Code Playgroud)

也就是说,首先打印Hello,然后\是一个换行符(然后是另一个换行符)。问题出在哪儿?

请参阅以下几个echo -e命令及其输出

man420@man420-X542UQ:~$ echo -e "HEllo\a\a\a\a\a\a\\\n"
HEllo\n
man420@man420-X542UQ:~$ echo -e "HEllo\\\n"
HEllo\n
man420@man420-X542UQ:~$ echo -e "HEllo\a\\\n"
HEllo\n
Run Code Online (Sandbox Code Playgroud)

Eli*_*gan 30

反斜杠由 特殊处理echo -e,但首先,根据 shell 的引用规则,它们有时会由 shell(在本例中为bash)进行特殊处理。

echo实际看到的论点是Hello\\n因为你已经传递-eecho,它特别对待反斜杠转义,并\\折叠为单个\. finaln没有被转义,所以它从字面上看。

这样做的原因是,在echo自身操作之前并与自身操作分开,shell在某些上下文中进行了特殊处理,\在其他上下文中则不进行特殊处理。未加引号\字符总是经过特殊处理的,单引号 \都从来没有经过特殊处理,但处理的双引号 \字符,如您运行的命令,是更加微妙和复杂。

当 shell 在命令中遇到双引号文本时,就像 一样"Hello\\\n"\当它位于一个字符之前时,它会被视为转义字符,而该字符本身可以在双引号内具有特殊含义,否则

  1. 因为\有时在里面有特殊含义,紧接在另一个之前的""a具有引用该第二个的效果。所以在双引号内,第一个被折叠成.\\\\\\
  2. 在前两个\字符之后,还有第三个\字符,它不受前两个字符的影响并且位于n. 但n不是一个在双引号内被特殊处理过的字符,所以\在这种情况下它不会被特殊处理。如此\n停留\n

效果是,在双引号中,\\\n被解释为\\n.

echo -esees 时\\n,第一个\从第二个中删除特殊含义,因此按字面echo打印\n该文本。


如果您的目标是打印Hello一个额外的换行符但没有反斜杠(这个问题最初是模棱两可的,而且我认为这是一个有用的例子),那么一个解决方案是删除\. 最后运行带有额外换行符的echo -e "Hello\\n"输出Hello

更好的解决方案是使用单引号并写入echo -e 'Hello\n'. 单引号是最强的引用形式。更好的解决方案通常是使用printf而不是echo,在这种情况下就是printf 'Hello\n\n'

如果您的目标是打印Hello\包括反斜杠,后跟一个额外的换行符,那么双引号方法是可能的,但很麻烦。要弄清楚,倒退:echo -e转换\\\\n到换行符,双引号转换\\\,所以你可以用六个反斜杠 ( echo -e "Hello\\\\\\n")来做,因为\\n变成\n由于一个反斜杠转义另一个。你也可以用 5 来做,因为双引号\n\没有被转义时会保留。

这说明了单引号的好处:只需将您想echo -e看到的任何内容放在单引号 ( echo -e 'Hello\\\n') 中。printf这里也不错。一种选择是printf 'Hello\\\n\n'。但printf真正令人眼前一亮的是,您可以插入其他参数。您可以使用printf '%s\n\n' 'Hello\', 插入第二个参数(字面意思是Hello\因为单引号不会改变任何内容)代替%s.