当我们在 shell 上输入一个简单的命令时会发生什么?

当我们在 shell 上输入一个简单的命令时会发生什么?

我有一个关于执行简单命令的简单问题。根据我的理解,当我们ls在交互式 shell 中键入命令时,

  1. Shell 解释该命令。
  2. Shell 创建一个子进程并在子进程上执行命令。
  3. Shell 等待子进程完成。

如果我的理解是正确的,我们在 shell 提示符下输入的一个简单命令将在子进程上执行,并且该命令的结果不会影响当前 shell 的环境。

如果是这样,那么像 之类的内置命令怎么样cd?如果cd在子进程上执行并且不会影响当前shell的环境,那么如何更改当前shell的工作目录呢?

答案1

shell只是一个程序,尽管它在系统中起着重要的作用。 Bash 以及我认为大多数其他常见 shell 都是用 C 实现的。两个最重要的本机 C系统调用用于创建子流程的是fork()exec()。这些功能通常也用高级语言实现,包括 shell。

  1. fork()

    “Fork”创建调用进程的副本作为其子进程。这就是系统上除第一个进程之外的几乎所有进程的方式(在里面) begin:作为启动它们的进程的副本。 Shell 语言实际上没有fork函数,但它确实包含生成子shell 的语法,它们是同一件事。

  2. exec()

    C 中实际上并没有exec()调用,但它通俗地指的是一组相关的函数;您可以看到带有 的列表man 3 exec,通常以以下开头:

    exec() 系列函数用新的进程映像替换当前进程映像...

    这正是它的作用:取代使用从可执行文件(例如/usr/bin/ls)加载的新内容来定义当前进程的内存堆栈的一部分。这就是为什么fork()在创建新进程时首先需要这样做——否则,调用进程将不再是原来的样子,而是变成别的东西;实际上不会创建新的进程。

乍一听,这可能是一种荒谬且低效的做事方式:为什么不直接使用一个命令从头开始创建一个新进程呢?事实上,由于以下几个原因,这可能不会那么有效:

  • 产生的“副本”fork()有点抽象,因为内核使用写时复制系统;真正需要创建的只是一个虚拟内存映射。如果复制然后立即调用exec(),则如果进程的活动修改了大部分数据,则实际上不必复制/创建大部分数据,因为进程不执行任何需要使用它的操作。

  • 子进程的各个重要方面(例如,其环境)不必单独复制或基于上下文的复杂分析等进行设置。它们只是假设与调用进程相同,并且这是我们熟悉的相当直观的系统。

有关“复制环境”到生成的子进程的确切含义的详细讨论,请参阅我的回答在这里

如果是这样,像 cd 这样的内置命令怎么样?

同样,它们只是在 C 中实现的。 chdir()与 和fork()一样exec(),是 Unix 平台对标准 C 的扩展的一部分,也是 shellcd命令的基础。从man 2 chdir

chdir() 将调用进程的当前工作目录更改为路径中指定的目录。

这不需要子进程——它会影响调用者。 shell 是一个交互式运行时口译员,这意味着当您向它提供命令时,它会执行用 shell 语言编写的代码。它通常不需要执行新进程来执行此操作,它会自行执行。

答案2

如果是这样,像 cd 这样的内置命令怎么样?如果 cd 在子进程上执行

你的逻辑错误就在这里。cd是 shell 内置命令,由 shell 专门解释并在进程内“执行”。您可以使用该type命令来确定命令是否是内置命令。

相关内容