了解Shell内置命令


12

bash手册中,写道

Builtin commands are contained >>> within <<< the shell itself

另外,这个答案指出

A built-in command is simply a command that the shell carries out itself,
instead of interpreting it as a request to load and run some
>>> other program <<<

在上运行compgen -bbash 4.4,我会收到所有shell内置命令的列表。我看到例如,[并且kill被列为shell内置程序。但是它们的实际位置是:

/usr/bin/[
/bin/kill

我认为这是builtin将命令编译为/bin/bash可执行文件的一种手段。因此,真正使我感到困惑的是:请纠正我,但是builtin当一个单独的命令实际上不属于shell的一部分时,它又如何成为a 呢?


1
某些命令最初作为单独的实用程序存在。他们的存在是为了符合POSIX标准,可移植性以及向后兼容。Shell实现了一些内置性能。可能还有其他原因,但这就是没有太多细节的原因。
Sergiy Kolodyazhnyy

1
我能想到的另一个原因是,shell需要一些内置命令,例如exec操纵文件描述符和eval 命令评估。不需要作为独立命令使用它们
Sergiy Kolodyazhnyy,

Answers:


16

内置在外壳程序中的命令通常是内置的,因为这样做可以提高性能。例如,调用外部对象 printf比使用内置对象慢printf

由于不需要内置某些实用程序,除非它们像特殊,否则它们cd也作为外部实用程序提供。这样一来,如果脚本由不提供内置等效项的Shell解释,则脚本不会中断。

一些Shell的内置插件还提供了对外部等效命令的扩展。printf例如Bash的

$ printf -v message 'Hello %s' "world"
$ echo "$message"
Hello world

(打印到变量),因为外部用户/usr/bin/printf无法访问当前shell会话中的shell变量(并且无法更改它们),因此外部根本无法执行此操作。

内置的实用工具也并没有有限制他们的扩展命令行必须超过一定的长度短。在做

printf '%s\n' *

因此,如果printf是shell内置命令,则是安全的。命令行长度的限制来自execve()用于执行外部命令的C库函数。如果命令行和当前环境大于ARG_MAX字节(请参见getconf ARG_MAX外壳程序),则对的调用execve()将失败。如果该实用程序内置在外壳中,execve()则不必调用。

内置实用程序优先于中的实用程序$PATH。要禁用中的内置命令bash,请使用例如

enable -n printf

需要在shell中构建实用程序的简短列表(摘自POSIX标准的特殊内置列表

break
colon (:)
continue
dot (.)
eval
exec
exit
export
readonly
return
set
shift
times
trap
unset

由于它们直接操纵了当前shell会话的环境和程序流,因此需要内置它们。外部实用程序将无法执行此操作。

有趣的是,cd它不是该列表的一部分,但是POSIX对此表示了以下看法:

由于cd会影响当前的Shell执行环境,因此始终将其作为Shell常规内置项提供。如果在子shell或单独的实用程序执行环境中调用它,例如以下之一:

(cd /tmp)
nohup cd
find . -exec cd {} \;

它不会影响调用者环境的工作目录。

因此,我假设“特殊”的内置程序不能具有外部对应项,而cd理论上可以(但效果不是很大)。


IIRC,chdir/ cd是外部的二进制文件很早就Unix系统/预Unix的前fork推出。
Xophmeister

@Xophmeister Solaris 11.4(测试版)仍然具有/usr/bin/cd,但实际上不会更改当前的工作目录。它的手册说:/usr/bin/cd对调用过程没有影响,但是可以用来确定是否可以将给定目录设置为当前目录。
库萨兰达

2
内置的另一个相当具体的原因:内置kill也很不错,因为它不需要派生其他进程,如果您已达到进程数限制,则很好。
德罗伯特

7

您(非常容易理解)对某些内置函数作为内置函数作为外部命令同时存在的事实感到困惑。因此,举例来说,尽管有一个正确的/bin/[命令,但这并不意味着其“实际位置”在中/bin

任何简单的测试方法都是type使用-a开关运行,该开关将显示命令的所有可用实例。在我的Arch系统上,它显示:

$ type -a [
[ is a shell builtin
[ is /sbin/[
[ is /usr/sbin/[
[ is /usr/bin/[

请注意/sbin/usr/sbin/bin都是指向的符号链接/usr/bin,因此只有一个外部[

$ readlink -f /usr/sbin /sbin /bin/
/usr/bin
/usr/bin
/usr/bin

如您所见,[它既是内置命令,也是外部命令,其他各种Shell内置命令也是如此。但是,这并不能改变它们也是shell内置程序的事实,它们已编译到shell本身中。


为什么发行。为已经存在的内部命令提供单独的外部命令?为什么它们重复?
LoveWithMaths

1
@linuxuser POSIX需要其中一些实用程序,并且您不知道用户碰巧使用的shell是否也会提供内置函数。不要将它们视为操作系统的内部命令,它们只是外壳程序的内部命令,外壳程序可以更改。
terdon

我现在有一个疑问,如果内部命令是由Shell提供的;那谁提供外部命令呢?就像我观察到许多内部和外部命令一样,但是我明确地安装了它们;那么谁提供外部命令?发行版可以为他们提供正确的信息吗?
LoveWithMaths

@linuxuser取决于命令和操作系统。例如,在我的Arch Linux上,/bin/printf是通过coreutils软件包和/bin/kill通过安装的util-linux
terdon

对不起,但我仍然不清楚,发行版提供了上述哪一项?以及发行版未提供的其他内容,则由谁提供。
LoveWithMaths
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.