$ which echo
echo: shell built-in command.
$ which ls
/bin/ls
$ which cat
/bin/cat
为什么回声不喜欢一个独立的工具ls
,ps
,cat
等?为什么它是特定于外壳的?有什么好的理由吗?
echo
最肯定是 Bash内置的。实际上,它是每个主要现代外壳中的内置组件。
$ which echo
echo: shell built-in command.
$ which ls
/bin/ls
$ which cat
/bin/cat
为什么回声不喜欢一个独立的工具ls
,ps
,cat
等?为什么它是特定于外壳的?有什么好的理由吗?
echo
最肯定是 Bash内置的。实际上,它是每个主要现代外壳中的内置组件。
Answers:
有两类内建函数:
有些命令必须内置到Shell程序本身中,因为如果它们在外部,则它们将无法工作。
cd
之所以这样,是因为如果它在外部,则只能更改自己的目录;它不会影响外壳程序的当前工作目录。(另请参见:为什么cd
不是程序?)
外壳中内置了另一类命令,纯粹是为了提高效率。
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
。根据该文件中的时间戳,可以证明echo
1980年肯定不在外壳中。
同一目录中还包含一个名为的文件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..
*/
print
ksh 的内置命令,该命令的行为类似于echo
。该命令也存在于ISC的AT&T Unix SVR4 2.1 i386之类的东西中。print "\012"
产生与echo相同的结果。想知道为什么ksh具有打印功能而不内置回显功能?反正真的很有趣。
内置某些命令的第三个原因:当无法运行外部命令时可以使用它们。
有时,系统变得如此混乱,以致该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,该怎么办?
ps
命令,因此必须通过手动查找PID /proc
。
which
是一个运行的bash别名,alias | /usr/bin/which --read-alias ...
因此外部which
可以识别别名(但仍然不是内置的)。我不能决定是否考虑这种辉煌或变态。
根据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内置程序。但这似乎无关紧要,因为这些脚本仍然可以在任何地方正常工作。
type
。
尽管当今大多数shell都包含内置的echo
,但GNU CoreUtils还包括它的独立实现:
$ which echo
/bin/echo
$ dpkg -S /bin/echo
coreutils: /bin/echo
听起来好像您没有安装GNU Coreutils(默认情况下,大多数基于linux的台式机和服务器操作系统都已安装了它,但是嵌入式linux或其他UNIX可能会使用替代的shell实用程序集合)。
顺便说一句:如果您查看Busybox,您会看到ls
,ps
并且cat
那里也是内置命令(或者至少是内置命令;它用于嵌入式系统,不需要的一切都可以忽略)。
/bin/echo
不存在的假设。它们只是表明内置函数优先echo
于PATH中的任何程序。
这是为什么echo
应该内置shell 的真正原因:
假设您在中有密码$PASSWORD
。您如何将其写入文件./password
?自然,大多数程序员都会写:
echo "$PASSWORD" >./password
但是,如果echo
不是内置的Shell,则密码将通过ps
信息泄露给所有用户。
当然,如果您想对此有所了解,可以找到一种无需使用即可存储密码的方法echo
,也许可以利用其他一些Shell功能:
cat >./password <<EOF
${PASSWORD}
EOF
但是,具有echo
内置功能是一个重要的安全带,因为将密码保存到文件的最明显的方法也应该起作用。