MS.*_*Kim 38 shell process subshell
我有一个关于执行简单命令的简单问题。根据我的理解,当我们ls
在交互式 shell 中键入命令时,
如果我的理解是正确的,我们在 shell 提示符下键入的一个简单命令会在子进程上执行,并且该命令的结果不会影响当前 shell 的环境。
如果是这样,那么内置命令cd
呢?如果cd
在子进程上执行并且不能影响当前shell的环境,那么如何更改当前shell的工作目录?
gol*_*cks 36
shell 只是一个程序,虽然它在系统中扮演着重要的角色。Bash 和我假设大多数其他常见的 shell 都是用 C 实现的。用于创建子进程的两个最重要的本地 C系统调用是fork()
和exec()
。这些函数通常也用高级语言实现,包括 shell。
fork()
“Fork”创建调用进程的副本作为其子进程。这就是系统上除第一个(init)之外的几乎所有进程开始的方式:作为启动它们的进程的副本。Shell 语言实际上没有fork
函数,但它确实包含生成子shell 的语法,它们是相同的。
exec()
exec()
C 中实际上没有调用,但它通俗地指的是一组相关的函数;您可以看到带有 的列表man 3 exec
,通常以 开头:
exec() 系列函数用新的进程映像替换当前进程映像...
这正是它所做的:用从可执行文件(例如,/usr/bin/ls
)加载的新内容替换当前进程内存堆栈的定义部分。这就是为什么fork()
在创建一个新进程时首先是必要的——否则,调用进程不再是它原来的样子,而是变成别的东西;实际上不会创建新进程。
乍一看,这听起来像是一种荒谬且低效的做事方式:为什么不直接创建一个从头开始创建新进程的命令呢?事实上,由于以下几个原因,这可能不会那么有效:
产生的“复制”fork()
有点抽象,因为内核使用写时复制系统;真正需要创建的只是一个虚拟内存映射。如果复制然后立即调用exec()
,则大部分数据如果已被流程活动修改而将被复制,则实际上不必复制/创建,因为流程不执行任何需要使用它的事情。
子进程的各个重要方面(例如,其环境)不必根据对上下文的复杂分析等单独复制或设置。它们只是假设与调用进程的相同,并且这是我们熟悉的相当直观的系统。
有关将“环境复制”到生成的子进程的确切含义的详细讨论,请参阅我的答案here。
如果是这样,那么像 cd 这样的内置命令呢?
同样,这些只是在 C 中实现的 chdir()
,就像fork()
和一样exec()
,是标准 C 的 Unix 平台扩展的一部分,也是 shellcd
命令的基础。来自man 2 chdir
:
chdir() 将调用进程的当前工作目录更改为 path 中指定的目录。
这不需要子进程——它会影响调用者。shell 是一个交互式运行时解释器,这意味着它会在您提供命令时执行用 shell 语言编写的代码。它通常不需要执行新进程来执行此操作,它会自行完成。
如果是这样,那么像 cd 这样的内置命令呢?如果在子进程上执行 cd
这就是你逻辑的缺陷。cd
,作为 shell 内置函数,由 shell 专门解释并在进程内“执行”。您可以使用该type
命令来确定某个命令是否内置。
归档时间: |
|
查看次数: |
19571 次 |
最近记录: |