问题描述
我注意到我的Ubuntu MATE 17.04系统上有一个二进制可执行文件/bin/echo
。
我想,那很奇怪,因为
$ type echo
echo is a shell builtin
粗略测试表明,/bin/echo
与Bash内置echo
的作用相同:
$ /bin/echo foo
foo
$ /bin/echo $USER
zanna
那么,为什么有另一个版本的echo
与Bash程序分开,为什么或何时我想使用它?
最佳解决方案
如果打开bash
提示并键入echo
命令,该命令使用shell builtin而不是运行/bin/echo
。 /bin/echo
存在的重要原因是:
-
你并不总是使用shell。在各种情况下,您直接运行可执行文件而不是通过shell运行。
-
至少在理论上,一些壳没有内置的
echo
。实际上并不需要这样做。
要扩展#1,假设您要将名称以abc
开头的所有常规文件移动到src
中的任何位置到dest
。有几种方法可以做到这一点,但其中一种方法是:
find src -name 'abc*' -type f -exec mv -nv {} dest/ \;
但是假设,您想要查看将首先运行的每个命令,而不仅仅是运行它。那么,您可以将echo
添加到命令中,就像在其他上下文中一样:
find src -name 'abc*' -type f -exec echo mv -nv {} dest/ \;
但是find
不使用shell。那就是/bin/echo
。
除了find
与-exec
或-execdir
之外,/bin/echo
可执行文件将被其他程序调用,这些程序本身运行程序但不通过shell运行。这种情况发生在xargs
命令(与find
相关)以及许多其他上下文中,例如.desktop
文件的Exec=
行。另一个例子是当你运行sudo echo
时,如果sudo
正常工作,它可以方便地进行测试。
类似地,一些壳具有内置的printf
,但也存在/usr/bin/printf
。
您可能故意使用/bin/echo
的一个不太常见的原因是,如果您依赖它与shell提供的echo
命令之间的差异。 man echo
文件/bin/echo
; bash
中的help echo
记录了bash
内含蛋白。 echo
不是非常便携,因为不同的实现 – 跨操作系统和同一操作系统上的shell – support different options(例如,-e
)和differ in their treatment of backslashes。当然,最好避免依赖这些细节,而是使用printf
,即far more portable。
在bash
中,您可以使type
内置显示/bin/echo
– 假设/bin
在$PATH
中,因为它始终应该是 – 通过传递-a
标志:
$ type -a echo
echo is a shell builtin
echo is /bin/echo
次佳解决方案
Eliah做了很好的回答,但我想评论“为什么echo
的另一个版本与Bash程序分开”部分。这是错误的问题。
正确的问题是:why is this a builtin in the first place,它本来可以(并且是)一个完美的外部命令?
为简单起见,请看一下dash中的内置,一个可怜的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
其中有多少需要构建? [,echo,false,printf,pwd,test和true不需要内置:它们不会做任何只有内置函数可以做的事情(影响或获取外部命令不可用的shell状态)。 Bash的printf至少利用了内置函数:printf -v var将输出保存到变量var。 bash中的时间也很特殊:通过成为关键字,您可以在bash中计算任意命令列表(短划线没有等效时间)。 pwd也不需要是内置的 – 任何外部命令都将继承当前的工作目录(它也是一个external command)。 :是一个例外 – 你需要一个NOP,并且:是它。其余的执行外部命令可以轻松执行的操作。
因此,这些内置组件中的五分之一不需要内置。那为什么? dash
联机帮助页*实际上解释了为什么这些是内置的(强调我的):
Builtins
This section lists the builtin commands which are builtin because they
need to perform some operation that can't be performed by a separate
process. In addition to these, there are several other commands that may
be builtin for efficiency (e.g. printf(1), echo(1), test(1), etc).
这就是它们:这些内置存在,因为它们经常使用,交互式和脚本使用,并且它们的功能非常简单,shell可以完成这项工作。所以它发生了:一些(大多数?)shell接受了这项工作。**从2.9 BSD返回sh
,你将找不到echo
内置。
所以,完全有可能一个最小的shell可以跳过实现像builtins这样的命令(我不认为任何当前的shell都可以)。 GNU coreutils项目并不假设你要在特定的shell中运行它们,而POSIX需要这些命令。因此,coreutils无论如何都会提供这些,并跳过那些在shell之外没有任何意义的东西。
*这几乎与the corresponding manpage text for the Almquist shell相同,后者是Debian Almquist shell的基础。
** zsh
将这个想法发挥到极致:通过加载各种模块获得的命令,如zmv
,are things you wouldn’t think a shell need even get into。那时,真正的问题是:你为什么要使用bash而不是zsh,它拥有所有这些内置函数?