为什么cd不是程序?


128

我一直想知道为什么cd不是一个程序,但从未设法找到答案。

有人知道为什么会这样吗?



1
我记得读过(我找不到哪里)原始的unix cd命令是一个单独的程序。外壳专门处理它的原因是它不能fork,只是exec。当cd做,它会Exec的sh。我不知道这是不是真实的故事。
卡姆(Camh)2012年

重点是什么?如果要添加特殊处理,则最好只调用chdirsyscall。来源:v1 v5 v7(带有Bourne shell的第一版)
Mikel

2
@camh,这是一个真实的故事。我在Dennis M. Ritchie撰写的文章中也读到了这一点,“ Unix分时系统的演进”,AT&T贝尔实验室技术期刊63(6),第2部分,1984
。– jlliagre

@Mikel:我同意这似乎毫无意义,但我只是在讲cd一个我读过的故事。既然@jlliagre填写了详细信息,我对此方面显然是错误的。
camh 2012年

Answers:


171

cd命令修改“当前工作目录”,对吗?

“当前工作目录”是每个进程唯一的属性。

因此,如果cd是一个程序,它将像这样工作:

  1. cd foo
  2. cd过程开始
  3. cd进程将更改cd进程的目录
  4. cd进程退出
  5. 您的Shell仍具有与开始之前相同的状态,包括当前的工作目录。

8
您的五个步骤是正确的,但是“如果cd是程序,它将像这样工作”应该是“ cd在其外部程序实现中使用时,它确实会这样工作”。
jlliagre 2012年

1
我不是系统程序员,也不是真正了解与shell交互的来龙去脉,所以我希望shell公开其当前的工作目录,而cd则是访问和更改该属性的程序。在看了这个答案之后,要理解,由于多种原因,这可能并不是其实际工作方式的最佳选择。
杰森

108

cd除了内置的Shell外,实际上也是 POSIX兼容OS上的程序。他们必须为常规实用程序(例如)提供独立的可执行文件cd。例如,SolarisAIX,HP-UX和OS X就是这种情况。

显然,内建cd函数仍然是必需的,因为其外部实现不会更改当前的shell目录。但是,后者仍然有用。这是一个示例,显示了POSIX如何设想如何使用此cd命令:

find . -type d -exec cd {} \;

在POSIX系统上,此oneliner将报告您不允许进入的所有目录的错误消息cd。在大多数Gnu / Linux发行版中,它失败并显示以下错误消息:

find: `cd': No such file or directory

这是原始Unix合著者之一对您的问题“ 为什么cd不是程序? ” 的答案。在一个非常早的Unix实现中,cdchdir当时是拼写的)是一个外部程序。fork首次实施后,它只是意外停止了工作。

引用丹尼斯·里奇Dennis Ritchie)

在我们欢腾的过程中,发现chdir(更改当前目录)命令已停止工作。关于添加fork可能会破坏chdir调用的内容,有大量的代码阅读和焦虑的内省。最终,事实浮出水面:在旧系统中,chdir是一个普通命令;它调整了附加到终端的(唯一)进程的当前目录。在新系统下,chdir命令正确地更改了创建的进程的当前目录以执行该进程,但是该进程立即终止,并且对其父外壳没有任何影响!有必要使chdir成为特殊命令,该命令在shell内部执行。事实证明,几个类似命令的功能具有相同的属性,例如login。

资料来源: Dennis M. Ritchie,“ Unix分时系统的演进 ”,AT&T贝尔实验室技术期刊63(6),第2部分,1984年10月,第1577–93页

Unix版本1(1971年3月)chdir 手册页指出:

因为创建了一个新进程来执行每个命令,所以如果将chdir作为普通命令编写,它将无效。因此,它由Shell识别并执行。


10
……因此,很明显,POSIX规定必须有一个独立的cd可执行文件,但不应执行任何操作(除非使用错误的参数调用可能会发出错误消息)。奇怪的。
Ilmari Karonen

4
哦,如果这是真的,那不是POSIX中最愚蠢的事情。
哈兹2012年

5
POSIX CD页还表示,“自从CD影响当前shell执行环境,它总是作为一个shell常规内置提供的。”
Mikel

6
@Kaz,它们不是完全不同的东西。他们做同样的事情,但是只有内置的会影响当前的shell。
jlliagre 2012年

13
@Kaz:请不要在我只报告一个事实的时候傻叫我。您可能同意或不同意POSIX,但不要开枪。
jlliagre 2012年

47

从Bash简介(什么是shell?):

Shell还提供了一小组内置命令(builtins),这些命令实现了通过单独的实用程序无法获得或不方便获得的功能。例如,cdbreakcontinue,和 exec)不能外壳的外部实现,因为它们直接操纵壳本身。的historygetoptskill,或pwd内建命令,除其他外,可以在单独的事业中实现,但他们使用的内置命令更方便。后续各节将介绍所有的shell内建函数。


29

对于今年的愚人节,我编写了一个独立版本的cd

没有人开玩笑。叹。

任何不确定cd必须内置到外壳中的人都应下载,构建并尝试。

也阅读其手册页。:)


真有用的代码!:-)
dschulz 2012年

6
很高兴看到有人在努力使Gnu / Linux更符合POSIX。您的实现不仅是一个很好的笑话,而且实际上是Linux发行版中缺少的东西……
jlliagre 2012年

8
我认为明年我将再次引用POSIX问题进行尝试。;)
沃伦·扬

6年后:好吧,是吗?
彼得·施耐德

@ PeterA.Schneider:我以为很明显我在开玩笑,所以要明确地说,不,我实际上不会花很多力气将其投入到当前的OS和类似OS的项目中,例如Cygwin缺乏/bin/cd。如果您想采用我的代码并自行完成自己的任务,欢迎您这样做。
沃伦·杨

4

cdshell中的命令不能是单独的进程,因为在Unix中,没有机制可以更改其他进程(甚至是父进程)的当前工作目录。

如果cd进程不同,则必须更改其父级(shell)的当前工作目录,而这在Unix中是不可能的。而是cd一个特殊的内置命令。Shell调用像chdir()fchdir() 更改其自身当前工作目录这样的函数。

注意:内核为每个进程存储当前工作目录的索引节点号。子进程继承cwd自其父进程。


0

cd是shell内置命令。就这么简单。CD的人说了这一切。cd命令更改所有解释器和(在线程环境中)所有线程的工作目录。


因为外壳程序是一个环境,它关心您当前的工作目录($ PDW ...)或cdable_vars。最终,此内置方法是所有用户可见命令都应更改当前工作目录的方式。您可以通过以下方式进行测试:在不使用cd.c的情况下编译bash并尝试编写自己的cd脚本,该脚本尝试处理所有环境cdable_vars。这个问题也与开发者有关。我敢打赌他们可以更详细地回答您这个问题。

2
有一个非常良好的技术原因cd是内置。我建议您阅读排名最高的答案,并考虑如何改善您的答案。
托尔比约恩Ravn的安徒生

排名最高的答案是我读过的最糟糕的答案!可是 我是谁!

3
但这回答了为什么的问题。
托尔比约恩Ravn的安徒生

-1

我认为人们回答中缺少的一件事是当前目录是每个程序都可以更改的环境变量。如果使用“导出”命令查看当前环境变量列表,则将具有:

declare -x PWD="/home/erfan"

在您的结果中。因此,通过“ cd”命令,我们只想修改此内部变量。我认为,如果尝试,当然可以在shell中更改任何pty的PWD变量。喜欢:

cder    #change current PTY $PWD variable

但是我认为在正常情况下没有必要。换句话说,我们从bash(或任何shell)获得帮助来修改其定义的内部变量。


3
的确,Bourne Shell将当前工作目录(CWD)公开为$ PWD,但这不是主要的存储位置。实际位置在内核的每个进程结构中。因此,说CWD“是环境变量”是不正确的。如果按照您建议的方式工作,则此C两层代码将打印..路径,而不是您从其开始的路径:(#include <stdlib.h> int main(void) { chdir(".."); puts(getenv("PWD")); }顺便说一下,C壳将CWD公开为%cwd。)
Warren Young

让我们向您的应用添加其他几行。#include <stdlib.h> int main(void){chdir(“ ..”); puts(getenv(“ PWD”)); setenv(P“ PWD”,“ /”,1); puts(getenv(“ PWD”)); }结果将是什么?
Erfankam 2012年

3
这只会覆盖变量的值,而不会对CWD产生副作用。这是一个更好的测试,#include <unistd.h> int main(void) { char ac[99]; setenv("PWD", "/", 1); puts(getcwd(ac, sizeof(ac))); }它表明:它将显示您从中启动程序的目录,而不是/
沃伦·扬

我认为每个进程也都具有工作目录和路径变量。因此,通过chdir您只需更改进程的此属性。Shell也具有此属性,并且通过cd我们修改此属性。
Erfankam

4
不,我告诉您这$PWD仅对Bourne外壳有意义。这只是Shell与Shell脚本交流它知道的内容的一种方法,因此他们不必调用pwd即可查找它。任何独立程序(取决于的值)$PWD都是不可靠的。
沃伦·杨
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.