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

xen*_*ide 10 command-line

相比

echo -n "bar"
Run Code Online (Sandbox Code Playgroud)

echo "bar" -n
Run Code Online (Sandbox Code Playgroud)

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

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

Jan*_*der 18

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

历史上,UNIX 实用程序都是这样的——它们只在命令名称之后立即查找选项。很可能是 BSD 或 GNU 开创了更灵活的风格(尽管我可能是错的),因为即使现在POSIX 也将旧的方式指定为正确的(参见指南 9,也在man 3 getoptLinux 系统上)。无论如何,尽管现在大多数 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! --
Run Code Online (Sandbox Code Playgroud)

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

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

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


Das*_*son 9

其他答案表明您可以查看手册页以查看 -n 正在成为要回显的字符串的一部分。但是,我只想指出,没有 md5sum 就很容易对此进行调查,并使正在发生的事情变得不那么神秘。

[11:07:44][dasonk@Chloe:~]: echo -n "bar"
bar[11:07:48][dasonk@Chloe:~]: echo "bar" -n
bar -n
Run Code Online (Sandbox Code Playgroud)

  • +1 正好。如果管道未按预期运行,请分别测试每个部分。 (3认同)

Mik*_*kel 6

哇,每个人的解释都很长。

就这么简单:

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

删除| md5sum ,你会看到输出是不同的。


ica*_*pan 5

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

echo "bar" -n | md5sum

a3f8efa5dd10e90aee0963052e3650a1
Run Code Online (Sandbox Code Playgroud)

自己试试这个命令:

echo "bar -n" | md5sum
Run Code Online (Sandbox Code Playgroud)

您会注意到生成的 md5 是

a3f8efa5dd10e90aee0963052e3650a1
Run Code Online (Sandbox Code Playgroud)

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

在您的第一个示例代码中

echo -n "bar" | md5sum
Run Code Online (Sandbox Code Playgroud)

-n 用于表示不要在此回显后放置换行符。

你的第二个样本

echo "bar" -n | md5sum
Run Code Online (Sandbox Code Playgroud)

将 -n 视为文字文本。