zsh和bash之间的回声有什么区别?

问题描述

在bash中,在这种特定情况下,echo的行为如下:

$ bash -c 'echo "a\nb"'
a\nb

但是在zsh中,同一件事却大不相同...:

$ zsh -c 'echo "a\nb"'
a
b

然后在鱼中wi游,因为我很好奇:

$ fish -c 'echo "a\nb"'
a\nb

我确实意识到我可以跑步:

$ zsh -c 'echo -E "a\nb"'
a\nb

但是现在我担心我会因这种基本操作而陷入更多陷阱。 (因此,我对鱼类的研究:如果我必须对zsh进行如此低的修改,为什么不一直坚持下去,转而采用一种与众不同的东西呢?)

我自己没有找到任何文档来帮助澄清bash与zsh或直接列出差异的页面中的回声差异,所以这里有人可以将它们列出来吗?也许在进行切换时将我引导到任何可能产生影响的更广泛的陷阱,这将涵盖这种情况?

解决方法

通常最好使用printf以获得一致的结果。

如果您需要可预测的一致echo实现,则可以使用自己的函数覆盖它。

无论外壳如何,它的行为都一样。

echo(){ printf %s\\n "$*";}
echo "a\nb"
,

echo是好的并且可移植,仅用于打印结尾的文字字符串 换行符,但是对于任何更复杂的操作都没有好处,您可以 在this answer和 Shellcheck文档 here

即使根据 POSIX 每个实现都必须理解字符序列,而无需任何 您不能依靠的其他选择。您已经注意到, 例如,重击echo 'a\nb'会产生a\nb,但可以更改 使用xpg_echo shell选项:

$ echo 'a\nb'
a\nb
$ shopt -s xpg_echo
$ echo 'a\nb'
a
b

也许将我引向任何可能产生影响的更广泛的范围 进行切换时的陷阱,可以解决这种情况吗?

请注意,不同的echo实现之间存在不一致 不仅可以在外壳中显示出来,而且可以在其他地方显示出来 shell是间接使用的,例如在Makefile中。我曾经来过 整个Makefile中看起来像这样:

all:
    @echo "target\tdoes this"
    @echo "another-target\tdoes this"

make使用/ bin / sh运行这些命令,因此如果/ bin / sh是符号链接 在您的系统上扑朔迷离:

$ make
target\tdoes this
another-target\tdoes this

如果要在shell中进行移植,请使用printf。这个:

printf 'a\nb\n'

在大多数shell中应该产生相同的输出。