pre*_*ise 31 command-line coreutils
我试过了which cd,但它没有给出路径,而是返回了退出代码 1(用 进行了检查echo $?)。coreutilcd本身正在工作,所以可执行文件应该在那里,对吗?我也运行了findfor cd,但没有显示可执行文件。那它是如何实施的呢?
更新:
我不知道我是否应该在另一篇文章中问这个问题,但因为我认为这里很好,我正在扩展(?)这篇文章......所以答案实际上很简单,没有可执行文件 - 因为它是内置程序 — 但我发现一些内置程序(Fedora 中的 bash shell)具有可执行文件!所以内置 -> 我想没有可执行文件是不对的?也许一个解释什么是内置函数的答案(内置命令?),这实际上是这里的问题,而不是更多地关注cd......之前发布的一些好的链接表明内置函数不是程序......那么它们是什么?它们是如何工作的?它们只是外壳的函数或线程吗?
Vol*_*gel 50
cd不能是可执行文件在 shell 中,cd用于“进入另一个目录”,或者更正式地说,用于更改当前工作目录 (CWD)。不可能将其实现为外部命令:
当前工作目录是用于解释相对路径以获得可用于访问文件的完整路径的目录。
相对路径用在很多地方,一个进程的解释不应该影响另一个进程。
因此,每个进程都有自己的当前工作目录。
cd是关于更改 shell 进程的当前工作目录,例如,bash.
如果它是一个外部命令,路径中的一个可执行文件,运行该可执行文件将创建一个具有自己工作目录的进程,而不会影响当前 shell 的进程。即使外部命令会更改其目录,该更改也会在外部进程退出时消失。
因此,为cd. 该命令cd需要对当前运行的 shell 进程应用更改。
为此,它是shell的“内置命令”。
内置命令是行为类似于外部命令的命令,但在 shell中实现(因此cd不是 coreutils 的一部分)。这允许命令更改 shell 本身的状态,在这种情况下,调用chdir()see(参见man 2 chdir);
which现在,标题问题的答案很简单:
可执行命令which不能告诉我们 cd 是内置命令,因为可执行命令对内置命令一无所知。
type -a作为替代which,您可以使用type -a; 它可以看到可执行命令和内置命令;此外,它还能看到别名和函数——也在 shell 中实现:
$ type -a cd
cd is a shell builtin
$ type -a type
type is a shell builtin
$ type -a which
which is /usr/bin/which
which is /bin/which
Run Code Online (Sandbox Code Playgroud)
mur*_*uru 28
cd是POSIX 强制的shell 内置:
如果简单命令产生命令名称和可选参数列表,则应执行以下操作:
- 如果命令名称不包含任何斜杠,则应执行以下序列中的第一个成功步骤:
...
- 如果命令名称与下表中列出的实用程序名称匹配,则应调用该实用程序。
...
cd
...- 否则,应使用 PATH 搜索命令...
虽然这并没有明确说明它必须是内置的,但规范继续说,在描述中cd:
由于 cd 影响当前的 shell 执行环境,所以它总是作为 shell 常规内置提供。
从bash手册:
以下 shell 内置命令继承自 Bourne Shell。这些命令是按照 POSIX 标准的规定实现的。
...Run Code Online (Sandbox Code Playgroud)cd cd [-L|[-P [-e]]] [directory]
我想你可以想到一个cd不必是内置的架构。但是,您必须了解内置函数的含义。如果您在 shell 中编写特殊代码来为某个命令执行某些操作,那么您就接近拥有内置代码了。你做的越多,简单地拥有一个内置函数就越好。
例如,您可以让 shell 使用 IPC 与子进程通信,并且会有一个cd程序来检查目录是否存在以及您是否有权访问它,然后与 shell 通信以告诉它更改其目录。但是,您必须随后检查与您通信的进程是否是子进程(或仅与子进程进行特殊通信,例如特殊文件描述符、共享内存等),以及该进程是否实际上是运行受信任的cd程序或其他东西。那是一整罐蠕虫。
或者你可以有一个cd程序来进行chdir系统调用,然后启动一个新的 shell,将所有当前的环境变量应用于新的 shell,然后在完成后杀死它的父 shell(以某种方式)。1
更糟糕的是,您甚至可以拥有一个系统,其中一个进程可以改变其他进程的环境(我认为从技术上讲,您可以使用调试器来做到这一点)。然而,这样的系统将非常非常脆弱。
您会发现自己添加了越来越多的代码来保护这些方法,并且简单地将其设为内置方法要简单得多。
某个东西是可执行文件并不会阻止它成为内置文件。案例:
echo 和 testecho和test是 POSIX 强制的实用程序(/bin/echo和/bin/test)。然而,几乎所有流行的 shell 都有一个内置的echo和test. 同样,kill也可以作为程序使用。其他包括:
sleep (不常见)timefalsetrueprintf但是,在某些情况下,命令只能是内置命令。其中之一是cd。通常,如果未指定完整路径,并且命令名称与内置命令名称匹配,则会调用适合该命令的函数。取决于 shell,内置函数的行为和可执行文件的行为可能不同(这对于 来说尤其是一个问题echo,它具有截然不同的行为。如果您想确定行为,最好使用完整路径,并设置变量POSIXLY_CORRECT(即使这样也没有真正的保证)。
从技术上讲,没有什么能阻止您提供一个操作系统,它也是一个 shell,并且每个命令都是内置的。接近这个极端的是单体BusyBox。BusyBox 是一个单一的二进制文件,它(取决于调用它的名称)可以作为240 多个程序中的任何一个运行,包括 Almquist Shell ( ash)。如果您PATH在运行 BusyBox 时取消设置,那么您ash仍然可以访问 BusyBox 中可用的程序,而无需指定PATH. 它们接近于 shell 内置函数,除了 shell 本身是 BusyBox 的内置函数。
dash)如果看dash源码,执行线程是这样的(当然,使用管道等东西的时候还涉及到额外的功能):
main? cmdloop? evaltree?evalcommand
evalcommand然后用于findcommand确定命令是什么。如果它是内置的,那么:
cd
cd [-L|[-P [-e]]] [directory]
Run Code Online (Sandbox Code Playgroud)
cmdentry.u.cmd是一个struct( struct builtincmd),其成员之一是函数指针,具有典型的签名main:(int, char **)。的evalbltin函数调用(取决于内置是否是eval命令或不)任一evalcmd,或该函数指针。实际功能在各种源文件中定义。echo例如,是:
case CMDBUILTIN:
if (spclbltin > 0 || argc == 0) {
poplocalvars(1);
if (execcmd && argc > 1)
listsetvar(varlist.list, VEXPORT);
}
if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
if (exception == EXERROR && spclbltin <= 0) {
FORCEINTON;
break;
Run Code Online (Sandbox Code Playgroud)
本节中的所有源代码链接都是基于行号的,因此它们可能会更改,恕不另行通知。
1 POSIX 系统确实有一个cd可执行文件。
边注:
在 Unix 和 Linux 上有很多关于 shell 行为的优秀文章。特别是:
cd外部命令?如果到目前为止您还没有注意到列出的问题中的某个模式,那么几乎所有问题都涉及Stéphane Chazelas。
来自man which:
它返回将在当前环境中执行的文件(或链接)的路径名,如果它的参数在严格符合 POSIX 的 shell 中作为命令给出。它通过在 PATH 中搜索与参数名称匹配的可执行文件来实现这一点。它不遵循符号链接。
从 的描述中可以看出which,它只是在检查PATH。因此,如果您实现了 some bash function,它不会显示任何内容。最好将typecommand 与which.
例如在ls别名为ls --color=auto.
$ type ls
ls is aliased to `ls --color=auto'
$ which ls
/bin/ls
Run Code Online (Sandbox Code Playgroud)
如果您实现测试功能hello:
$ function hello() { for i in {1,2,3}; do echo Hello $i;done }
$ which hello
Run Code Online (Sandbox Code Playgroud)
which什么都不显示。但是type:
$ type hello
hello is a function
hello ()
{
for i in {1,2,3};
do
echo Hello $i;
done
}
Run Code Online (Sandbox Code Playgroud)
$ type cd
cd is a shell builtin
Run Code Online (Sandbox Code Playgroud)
这意味着这cd是一个内置的外壳,它在里面bash。中描述的所有 bash 内置man bash命令,在 SHELL BUILTIN COMMANDS 部分
SHELL BUILTIN COMMANDS
Unless otherwise noted, each builtin command documented in this section
as accepting options preceded by - accepts -- to signify the end of the
options. The :, true, false, and test builtins do not accept options
and do not treat -- specially. The exit, logout, break, continue, let,
and shift builtins accept and process arguments beginning with - with?
out requiring --. Other builtins that accept arguments but are not
specified as accepting options interpret arguments beginning with - as
invalid options and require -- to prevent this interpretation.
Run Code Online (Sandbox Code Playgroud)