为什么有一个/ bin / echo,为什么我要使用它?


52

我注意到/bin/echo我的Ubuntu MATE 17.04系统上有一个二进制可执行文件。

我认为这很奇怪,因为

$ type echo
echo is a shell builtin

光标测试表明,/bin/echo它可以执行与Bash内置函数相同的操作echo

$ /bin/echo foo
foo
$ /bin/echo $USER
zanna

那么,为什么还有echo不同于Bash程序的另一个版本,为什么以及何时要使用它呢?



2
@ bodhi.zazen即使不一样,它也很有用,因为它解决了这个问题的相反问题。这个问题询问为什么echo将其作为内置的shell提供,而这个问题询问为什么将其作为外部命令提供。
伊莱亚·卡根

3
原因之一是并非所有人都使用bash。我猜想/ bin / echo早于bash,开发人员发现将它作为内置文件包含在内而不是使用可执行文件是有用/有效的。
jamesqf

Answers:


88

如果打开bash提示并键入echo命令,则使用内置Shell而不是running /bin/echo。它仍然很重要的原因/bin/echo是:

  1. 您并不总是使用外壳。在各种情况下,您可以直接而不是通过Shell运行可执行文件。
  2. 至少从理论上讲,有些外壳没有echo内置的。这实际上不是必需的。

要在#1上进行扩展,假设您想将名称以abcin 开头的所有常规文件移动srcdest。有几种方法可以做到这一点,但其中一种是:

find src -name 'abc*' -type f -exec mv -nv {} dest/ \;

但是,假设您不仅要运行它,还希望看到将首先运行的每个命令。好了,那么您可以echo像在其他情况下一样,在命令前添加命令:

find src -name 'abc*' -type f -exec echo mv -nv {} dest/ \;

但是find不使用外壳。运行/bin/echo

除了find使用-exec或之外-execdir/bin/echo可执行文件还将由其他本身运行程序但不通过外壳运行的程序调用。这种情况发生xargs命令(其涉及find),以及在许多其他情况下,如所述Exec=线一个.desktop文件。另一个示例是运行时sudo echo,可以方便地测试其是否sudo正常运行。

同样,一些外壳具有printf内置功能,但/usr/bin/printf也存在。

您可能故意使用的一个不太常见的可能原因/bin/echo是,您是否依赖于它与echoShell提供的命令之间的差异。man echo文件/bin/echo; help echobashbash内置文件中。echo它不是非常可移植的,因为不同的实现(跨操作系统和同一操作系统上的Shell)都支持不同的选项(例如-e),并且对反斜杠的处理方式不同。当然,最好避免依赖这些细节,而要使用printf它,因为它更加可移植

bash,可以使type内置的表演/bin/echo,以及-假设/bin是你的$PATH,因为它始终应该是-通过它传递的-a标志

$ type -a echo
echo is a shell builtin
echo is /bin/echo

21
同时也因为POSIX规范说必须有一个。
格伦·杰克曼

4
@glennjackman我实际上希望有人发布有关该问题的答案,希望您决定这样做!这里也有一些微妙的参与,不过,既不的Debian,Ubuntu的,也不是GNU Coreutils的(也不整体GNU项目)尽量符合POSIX的一切。例如,POSIX坚持cd存在一个可执行文件(在运行时,可执行文件会更改目录并退出,从而使调用者离开之前的位置),并且某些OS拥有一个可执行文件在GNU标准中引用4.1可能会有所帮助。
伊莱亚·卡根

@EliahKagan:偶然地/ usr / bin / cd有一个用途:/ usr / bin / cd目录命令在该目录中运行该命令。如果目录更改失败,该命令将不会启动。
约书亚

4
@Joshua的更好用法cd只是测试访问给定目录的能力:如果/usr/bin/cd some/dir成功,则一次测试您已经测试过:a)some/dir存在,b)它是目录或指向一个目录的链接,以及c)您具有访问该目录所需的权限;所有这些都不会改变您自己的状态。
muru 17-10-1

1
@CarlWitthoft,请参阅为什么printf比echo好? 另外,除非您使用Windows,否则它/bin/echo不是\bin\echo。;)
通配符

31

Eliah在回答这个问题上做得很出色,但我想评论一下“为什么echo要从Bash程序中分离出另一个版本”。那是个错误的问题。

正确的问题是:为什么它本来是内置的,而原本可以是(并且是)完美的外部命令?

为简单起见,请看破折号中的内建函数,只有38个(bash有61个,作为比较,以的输出为准compgen -b):

.               continue        getopts         readonly        type
:               echo            hash            return          ulimit
[               eval            jobs            set             umask
alias           exec            kill            shift           unalias
bg              exit            local           test            unset
break           export          printf          times           wait
cd              false           pwd             trap
command         fg              read            true

其中有多少需要内置?[echofalseprintfpwdtest,和true不要需要是内建的:他们没有做任何事情,只有内置可以做(影响或获得壳状态,这不是提供给外部命令)。Bash printf至少利用了内置功能:printf -v var将输出保存到变量中vartimebash中的bash也很特殊:通过作为关键字,您可以为bash中的任意命令列表计时(破折号没有time等效项)。pwd也不需要是内置的-任何外部命令都将继承当前的工作目录(这也是一个外部命令)。:是一个例外-您需要一个NOP,:就是这样。其余的执行外部命令可以轻松执行的操作。

因此,这些内建函数的五分之一不需要内建。那为什么?手册dash *实际上解释了为什么这些是内置函数(强调我的):

内建
 本节列出了内置命令,因为它们是内置命令
 需要执行一些单独的操作无法执行的操作
 处理。除了这些,还有一些其他命令可能
 内置以提高效率(例如printf(1),echo(1),test(1)等)。

就是这样:这些内置函数之所以存在,是因为它们以交互方式在脚本中经常使用,并且它们的功能非常简单,因此Shell可以胜任。所以它发生:一些(?大多数)弹了在工作**回去。sh2.9 BSD,你不会找到一个echo内置。

因此,最小外壳程序完全有可能跳过实现诸如内置命令之类的命令(不过,我认为当前没有任何外壳程序可以这样做)。GNU coreutils项目不假定您要在特定的shell中运行它们,而POSIX需要这些命令。因此,coreutils仍然提供这些功能,并跳过外壳之外没有任何意义的功能。


*这几乎与Almquist shell的相应手册页文本相同,而破折号Debian Almquist shell正是基于此文本

** zsh将这个想法发挥到了极致:通过加载各种模块而获得的命令(例如zmv是您甚至认为Shell都不需要进入的东西。那时,真正的问题是:为什么要使用bash代替具有所有这些内置函数的zsh?


1
事实证明:也不需要是内置的。它不是内置的,这是愚蠢的。除非您要解决早期的急救软盘级别的问题(在这种情况下,我发现pwd也不可靠地工作),否则将其作为内置的唯一惩罚就是糟糕的性能。
约书亚记

5
@Joshua不,:因为外部设备实际上不是NOP PATH,当您真正想要做的只是明确地不执行任何操作时,您仍然需要查找,尝试执行命令等。:作为内置函数。
大师

2
实际上,Bash确实需要pwd内置才能使其正常工作,并且默认行为是显示“逻辑”路径(pwd -L)。 /bin/pwd只能实现pwd -P向您显示实际父目录的行为,而不是cd通过您显示的符号链接的行为。
彼得·科德斯

2
@PeterCordes pwd的状态会因b的存在而有所妥协PWD,但是是的,这也是bash使用内置状态来改善功能的一个实例
muru 17-10-1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.