在在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 -b
,bash 4.4
我收到所有 shell 内置命令的列表。例如,我看到[
和kill
被列为 shell 内置函数。但他们的实际位置是:
/usr/bin/[
/bin/kill
我认为这意味着builtin
命令被编译成/bin/bash
可执行文件。那么真正让我困惑的是:请纠正我,但是builtin
当它实际上不是 shell 的一部分时,它怎么可能是 a 呢?
答案1
内置到 shell 中的命令通常是内置的,因为这可以提高性能。呼叫外部的 printf
例如,比使用内置的printf
.
由于某些实用程序不需要内置,除非它们是特殊的,例如cd
,它们也提供为外部的公用事业。这样,如果脚本由不提供内置等效项的 shell 解释,则脚本不会中断。
某些 shell 的内置命令还提供对外部等效命令的扩展。例如, Bashprintf
能够做到
$ 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
shell),调用execve()
将会失败。如果该实用程序内置于 shell 中,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
理论上可以有(但它不会做太多事情)。
答案2
您(非常可以理解)对某些内置函数的存在感到困惑两个都作为内置函数和作为外部命令。因此,虽然您是对的,例如有一个/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 本身中。