为什么 echo "bar" -n 与 echo -n "bar" 不同?

为什么 echo "bar" -n 与 echo -n "bar" 不同?

比较

echo -n "bar"

echo "bar" -n

前者做什么认为它应该这样做(打印“bar”而不换行),而后者则没有。这是一个错误还是设计使然?为什么它与许多 cli 程序不同,不能移动选项?例如,tail -f /var/log/messages与 完全相同tail /var/log/messages -f。当我忘记我想要前者时,有时我会做后者,因为在内部选项和参数通常会被重新排列获取选择

更新:是的,我最初削弱了我的问题。我删除了你必须查看历史记录才能使某些答案有意义的削弱。

答案1

正如大多数其他人所观察到的,如果将“-n”放置在命令之后以外的任何位置,则按字面解释echo

从历史上看,UNIX 实用程序都是这样的——它们仅在命令名称之后立即查找选项。很可能是 BSD 或 GNU 开创了更灵活的风格(尽管我可能是错的),即使是现在POSIX 指定旧方法是正确的(参见指南 9,以及man 3 getopt在 Linux 系统上)。不管怎样,尽管现在大多数 Linux 实用程序都使用新的风格,但还是有一些坚持不懈的人,比如echo.

Echo从标准角度来说是一团糟,因为至少有两个根本冲突的版本当 POSIX 诞生时,它就已经开始发挥作用了。一方面,您有 SYSV 风格,它解释反斜杠转义字符,但按字面处理其参数,不接受任何选项。另一方面,您有 BSD 风格,它将首字母视为-n特殊情况,并按字面输出绝对所有其他内容。由于echo它非常方便,因此您有数千个依赖于一种行为或另一种行为的 shell 脚本:

echo Usage: my_awesome_script '[-a]' '[-b]' '[-c]' '[-n]'
echo -a does a thing.
echo -b does something else.
echo -c makes sure -a works right.
echo -- DON\'T USE -n -- it\'s not finished! --

由于“按字面意思对待所有内容”的语义,甚至不可能在echo不破坏事物的情况下添加新选项。如果 GNU 在其上使用灵活的选项方案,地狱就会崩溃。

顺便说一句,为了获得 Bourne shell 实现之间的最佳兼容性,使用printf而不是echo

更新解释为什么echo特别不使用灵活选项。

答案2

其他答案都直指这一点,您可以查看手册页以了解 -n 正在成为要回显的字符串的一部分。不过,我只想指出,无需 md5sum 即可轻松调查此问题,并使发生的事情不那么神秘。

[11:07:44][dasonk@Chloe:~]: echo -n "bar"
bar[11:07:48][dasonk@Chloe:~]: echo "bar" -n
bar -n

答案3

哇,大家的解释都很长。

就这么简单:

-n如果它出现在字符串之前,则它是一个选项,否则它只是另一个要回显的字符串。

删除它| md5sum ,您会看到输出有所不同。

答案4

从简单的检查来看,这不是设计上的错误......

echo "bar" -n | md5sum

a3f8efa5dd10e90aee0963052e3650a1

亲自尝试一下这个命令:

echo "bar -n" | md5sum

您会注意到生成的 md5 是

a3f8efa5dd10e90aee0963052e3650a1

您只是在 echo 中混淆了 -n 的使用。

在您的第一个示例代码中

echo -n "bar" | md5sum

-n 用于表示不要在此回显之后添加换行符。

您的第二个样本

echo "bar" -n | md5sum

将 -n 视为文字文本。

相关内容