为什么echo是内置命令的shell?


34
$ which echo
echo: shell built-in command.
$ which ls
/bin/ls
$ which cat
/bin/cat

为什么回声不喜欢一个独立的工具lspscat等?为什么它是特定于外壳的?有什么好的理由吗?


5
请记住,这是特定于外壳的。ZSH内置了它,而BASH则没有。
tsvallender

21
@tsv:echo最肯定 Bash内置的。实际上,它是每个主要现代外壳中的内置组件。
暂停,直到另行通知。

Answers:


71

有两类内建函数:

  1. 有些命令必须内置到Shell程序本身中,因为如果它们在外部,则它们将无法工作。

    cd之所以这样,是因为如果它在外部,则只能更改自己的目录;它不会影响外壳程序的当前工作目录。(另请参见:为什么cd不是程序?

  2. 外壳中内置了另一类命令,纯粹是为了提高效率。

    手册页有其中提到上内建一个部分,和作为命令的例子在这个类。dash printfechotest

Unix系统始终在该第二类中为命令提供单独的可执行文件。这些单独的可执行文件在我使用过的每个Unixy系统上仍然可用,即使它们也已内置在您可能使用的每个shell中。(POSIX实际上要求这些可执行文件存在。)

我相信echo,AT&T Unix System V版本3.1已内置到外壳中。我基于比较两个不同版本的AT&T 3B1系列Unix系统的手册。有人仔细扫描了1986年的这些手册并放在网上 ; 这些对应于SVR3的原始版本。您可以看到UNIX System V用户手册,第II卷echo第523页的列表中没有该命令,如果命令是内置在shell中的话,您会期望它在其中。在从1987年SVR3.1手册我的本地文件拷贝,列在本章节。echo

我很确定这不是AT&T带回国内的Berkeley CSRG创新。4.3BSD与1986年的SVR3于同年问世,但是如果您查看4.3BSD的sh.1联机帮助页,则会发现该echo命令不在内置命令的“特殊命令”部分中。如果CSRG这样做,那么我们就需要一个有证件的消息来源来证明这一点。

在这一点上,您可能想知道是否echo内置于SVR3.1之前的外壳中,并且直到那时才对此事实进行记录。我可以使用的最新的SVR3之前的AT&T Unix源代码在PDP-11 System III tarball中,您将在其中找到Bourne shell源代码。您不会echo在的内置命令表中找到该命令/usr/src/cmd/sh/msg.c。根据该文件中的时间戳,可以证明echo1980年肯定不在外壳中。


琐事

同一目录中还包含一个名为的文件builtin.c,该文件不包含该问题的任何内容,但我们确实发现了以下有趣的注释:

/*      
    builtin commands are those that Bourne did not intend
    to be part of his shell.
    Redirection of i/o, or rather the lack of it, is still a
    problem..
*/      

在您提到的SysV UM第II卷的第385页上,有printksh 的内置命令,该命令的行为类似于echo。该命令也存在于ISC的AT&T Unix SVR4 2.1 i386之类的东西中。print "\012"产生与echo相同的结果。想知道为什么ksh具有打印功能而不内置回显功能?反正真的很有趣。

几年前偷走了多少这样的宝石,等待2016年的编辑发掘?+1
iruvar

+1。谢谢。您能否提供源代码(参考)以构建内置命令,以便进行(系统的)阅读/学习?
蒂姆(Tim)

我想找到一些参考,手册或标准来系统地阅读或学习。我试图在bash参考手册和POSIX规范中查找它。但是我找不到。我不确定是否想念他们。
蒂姆(Tim)

@Tim:正如这里的其他答案所解释的,某些命令必须内置到外壳中,否则它们将无法执行工作。所有其他纯粹是可选的。实际上,这实际上就是我的Bourne shell源代码片段所说的。由于将此类命令构建到外壳中是可选的,因此权威性的理论只能给出一个实施者的意见。
沃伦·杨

19

内置某些命令的第三个原因:当无法运行外部命令时可以使用它们。

有时,系统变得如此混乱,以致该ls命令不起作用。在某些情况下,echo *仍然可以使用。

另一个(更重要!)示例是kill:如果系统用完了可用的PID,则无法运行/bin/kill(因为它需要一个PID :-),但是内置的kill将起作用。

Btw。which是外部命令(至少在bash中不是内部命令),因此它不能列出内部命令。例如:

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

不要忘记,几乎所有外部可执行文件都依赖于库文件。有时会发生灾难,并且无法加载这些库(建议:ldconfig除非您确切地知道自己在做什么,否则不要发布)。另外,如果您破坏了/ bin或更糟的/ sbin分区,但仍然加载了shell,该怎么办?
LawrenceC

如果您用完了PID,可能很难找出想要杀死的PID。您无法运行ps命令,因此必须通过手动查找PID /proc
kasperd 2015年

尽管(至少)在CentOS上,它which是一个运行的bash别名,alias | /usr/bin/which --read-alias ...因此外部which 可以识别别名(但仍然不是内置的)。我不能决定是否考虑这种辉煌或变态。
dave_thompson_085 '16

当ls命令不再起作用时,我认为您应该将驱动器安装为从属驱动器而不是引导/主驱动器,并以这种方式修复文件结构。我不确定如何用echo修复这种程度的系统损坏,除非您将echo>放入文件中,这将需要很长时间才能修复。当然,您可以编写一个Bash脚本来修复系统结构。
jonnyjandles

13

根据Bash参考手册,这是为了方便。

Shell还提供了一小组内置命令(builtins),这些命令实现了通过单独的实用程序无法获得或不方便获得的功能。例如,cd,break,continue和exec)不能在Shell外部实现,因为它们直接操纵Shell本身。历史记录,getopts,kill或pwd内置程序等可以在单独的实用程序中实现,但是用作内置命令更方便。后续各节将介绍所有的shell内建函数。

高级Bash脚本指南》有更详细的说明:

“内置命令是包含在Bash工具集中的命令,实际上是内置命令。这是出于性能方面的考虑-内置命令的执行速度比外部命令要快,后者通常需要分叉 1 个单独的进程-或特定的内置命令需要直接执行访问外壳内部。”

还请注意,echo在某些系统上,它确实作为独立实用程序存在。这是达尔文系统(MacOSX 10.5.8-Leopard)上的功能

$ uname -a
Darwin host.foo.org 9.8.0 Darwin Kernel Version 9.8.0: Wed Jul 15 16:55:01 PDT 2009; root:xnu-1228.15.4~1/RELEASE_I386 i386
$ bash --version
GNU bash, version 3.2.17(1)-release (i386-apple-darwin9.0)
Copyright (C) 2005 Free Software Foundation, Inc.
$ which echo
/bin/echo

echo也可以作为内置程序使用,但显然我的脚本在Mac上使用/ bin / echo,并且在大多数Linux和FreeBSD系统上使用Bash内置程序。但这似乎无关紧要,因为这些脚本仍然可以在任何地方正常工作。


3
说到shell内置,您应该使用“类型”而不是“哪个”。
泰迪

谢谢@泰迪。当我记得时,我已经开始这样做了。多亏了,生活变得更好type
Stefan Lasiewski 2011年


2

尽管当今大多数shell都包含内置的echo,但GNU CoreUtils还包括它的独立实现:

$ which echo
/bin/echo
$ dpkg -S /bin/echo
coreutils: /bin/echo

听起来好像您没有安装GNU Coreutils(默认情况下,大多数基于linux的台式机和服务器操作系统都已安装了它,但是嵌入式linux或其他UNIX可能会使用替代的shell实用程序集合)。

顺便说一句:如果您查看Busybox,您会看到lsps并且cat那里也是内置命令(或者至少是内置命令;它用于嵌入式系统,不需要的一切都可以忽略)。


3
原始海报的测试不支持/bin/echo不存在的假设。它们只是表明内置函数优先echo于PATH中的任何程序。
沃伦·杨

1

这是为什么echo应该内置shell 的真正原因:

假设您在中有密码$PASSWORD。您如何将其写入文件./password?自然,大多数程序员都会写:

echo "$PASSWORD" >./password

但是,如果echo不是内置的Shell,则密码将通过ps信息泄露给所有用户。

当然,如果您想对此有所了解,可以找到一种无需使用即可存储密码的方法echo,也许可以利用其他一些Shell功能:

cat >./password <<EOF
${PASSWORD}
EOF

但是,具有echo内置功能是一个重要的安全带,因为将密码保存到文件的最明显的方法也应该起作用。


3
尽管这是有用的副作用,但我怀疑这是非常令人怀疑的。
plugwash

@DepressedDaniel:你有什么后盾?您用来支持答案的参考文献在哪里?
小丑
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.