zsh和bash在回显方面有哪些区别?

4
在Bash中,在这种特定情况下,echo的行为如下:
$ bash -c 'echo "a\nb"'
a\nb

但是在zsh中,同样的事情变得非常不同......:

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

顺便提一句,我在Fish Shell中尝试了一下,因为我很好奇:

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

我意识到我可以运行:

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

但现在我担心我即将在这么基础的操作上遇到更多的问题。(因此我进行了有关fish的调查:如果我将不得不在如此低的层面上对zsh进行更改,为什么不彻底切换到明显不同的东西呢?) 我自己没有找到任何有助于澄清bash和zsh之间echo区别的文档或直接列出它们之间差异的页面,所以有人能否在这里列出它们?也许可以指引我转换时可能具有广泛影响的其他需要注意的地方吗?

3
除非没有任何影响,否则不要使用echo来打印数据。无论使用哪种shell,printf %s\\n "a\nb"的行为都是相同的。 - Léa Gris
3个回答

4

通常偏向于使用printf以获得一致的结果。

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

这将在不同的shell中表现出相同的行为。

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

2

echo 只适用于打印以换行符结尾的字面字符串,但对于更复杂的内容则不够好用。您可以在这个答案和Shellcheck文档here中了解更多信息。

尽管根据POSIX的规定,每个实现都必须理解没有任何其他选项的字符序列,但您不能依赖于此。正如您已经注意到的,在Bash中,例如echo 'a\nb'会产生a\nb,但可以通过xpg_echo shell选项进行更改:

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

也许你能指引我了解更广泛的可能会影响转换的问题,包括这种情况?

请注意,在不同的 echo 实现之间的不一致性不仅可以在 shell 中表现出来,而且还可以在间接使用 shell 的其他地方表现出来,例如在 Makefile 中。 我曾经遇到过像这样的 Makefile:

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

make 使用 /bin/sh 来运行这些命令,因此如果在您的系统上 /bin/sh 是指向 bash 的符号链接,则会得到以下结果:

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

如果您想在shell中实现可移植性,请使用printf。这样做:
printf 'a\nb\n'

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


0

无论从哪个shell解释器调用,echo都提供相同的输出。

区别在于每个shell将如何将标准输出缓冲区打印到屏幕上。zsh会自动解释转义字符/序列(即"\n\t\v\r..."或ANSI转义序列),而bash则不会。

使用bash,您必须提供-e标志才能打印换行符:

#Input:
echo "[text-to-print]\n[text-to-print-on-newline]" 
#Output:
[text-to-print]\n[text-to-print-on-newline]

#Input:
echo -e "[text-to-print]\n[text-to-print-on-newline]" 
#Output: 
[text-to-print]
[text-to-print-on-newline]

使用zsh,解释器会自动进行转义序列的解释,并且无论是否使用-e标志,输出结果都是相同的。
#Input:
echo "[text-to-print]\n[text-to-print-on-newline]"
#Output:
[text-to-print]
[text-to-print-on-newline]

#Input:
echo -e "[text-to-print]\n[text-to-print-on-newline]"
#Output:
[text-to-print]
[text-to-print-on-newline]

这应该可以解决您在shell解释器之间看到的差异。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接