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
。因为你已经传递-e
到echo
,它特别对待反斜杠转义,并\\
折叠为单个\
. finaln
没有被转义,所以它从字面上看。
这样做的原因是,在echo
自身操作之前并与自身操作分开,shell在某些上下文中进行了特殊处理,\
而在其他上下文中则不进行特殊处理。未加引号\
字符总是经过特殊处理的,单引号 \
都从来没有经过特殊处理,但处理的双引号 \
字符,如您运行的命令,是更加微妙和复杂。
当 shell 在命令中遇到双引号文本时,就像 一样"Hello\\\n"
,\
当它位于一个字符之前时,它会被视为转义字符,而该字符本身可以在双引号内具有特殊含义,否则。
\
有时在里面有特殊含义,紧接在另一个之前的""
a具有引用该第二个的效果。所以在双引号内,第一个被折叠成.\
\
\
\\
\
\
字符之后,还有第三个\
字符,它不受前两个字符的影响并且位于n
. 但n
不是一个在双引号内被特殊处理过的字符,所以\
在这种情况下它不会被特殊处理。如此\n
停留\n
。效果是,在双引号中,\\\n
被解释为\\n
.
当echo -e
sees 时\\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
.