Warum ist CD kein Programm?

129

Ich habe mich immer gefragt, warum cdes kein Programm gibt, aber ich habe es nie geschafft, die Antwort zu finden.

Weiß jemand, warum das so ist?

AkshaiShah
quelle
1
Ich erinnere mich, dass ich gelesen habe (ich kann nicht finden, wo), dass der ursprüngliche Unix- cdBefehl ein separates Programm war. Die Schale behandelt es speziell, dass sie tat es nicht fork, einfach exec. Und wenn cdes fertig war, würde es exekutieren sh. Ich weiß nicht, ob dies eine wahre Geschichte ist.
camh
Was wäre der Punkt? Wenn es eine spezielle Behandlung geben soll, kann es auch einfach den chdirSyscall aufrufen . Quellen: v1 v5 v7 (erste Version mit Bourne-Shell)
Mikel
2
@camh, das ist eine wahre Geschichte. Das habe ich auch in einem Artikel von Dennis M. Ritchie, "Die Entwicklung des Unix-Zeitverteilungssystems", AT & T Bell Laboratories, Technical Journal 63 (6), Teil 2, Oktober 1984,
gelesen
@Mikel: Ich stimme zu, dass es sinnlos erscheint, aber ich habe nur eine Geschichte darüber weitergegeben cd, die ich gelesen hatte. Ich habe mich eindeutig geirrt, nachdem @jlliagre die Details ausgefüllt hat.
camh

Antworten:

172

Der cdBefehl ändert das "aktuelle Arbeitsverzeichnis", richtig?

"aktuelles Arbeitsverzeichnis" ist eine Eigenschaft, die für jeden Prozess eindeutig ist.

Wenn also cdein Programm wäre, würde es so funktionieren:

  1. cd foo
  2. Der cdProzess beginnt
  3. Der cdProzess ändert das Verzeichnis für den CD-Prozess
  4. Der cdProzess wird beendet
  5. Ihre Shell hat immer noch denselben Status, einschließlich des aktuellen Arbeitsverzeichnisses, wie vor dem Start.
Daniel Pittman
quelle
8
Ihre fünf Schritte sind korrekt, aber "wenn cdein Programm so funktionieren würde" sollte "wenn cdes in seiner externen Programmimplementierung verwendet wird, funktioniert es so" lauten .
Juli
1
Da ich kein Systemprogrammierer bin und keine tiefgreifenden Kenntnisse über die Vor- und Nachteile der Interaktion mit der Shell habe, hätte ich erwartet, dass die Shell ihr aktuelles Arbeitsverzeichnis freigibt und CD ein Programm ist, das auf diese Eigenschaft zugreift und sie ändert. Nach Betrachtung dieser Antwort zu verstehen, dass dies aus vielen Gründen möglicherweise nicht optimal funktioniert.
Jason
108

cdist nicht nur eine eingebaute Shell, sondern auch ein Programm für POSIX-kompatible Betriebssysteme. Sie müssen unabhängige ausführbare Dateien für reguläre Dienstprogramme wie bereitstellen cd. Dies ist beispielsweise bei Solaris , AIX , HP-UX und OS X der Fall .

Ein Builtin cdist natürlich immer noch obligatorisch, da seine externe Implementierung das aktuelle Shell-Verzeichnis nicht ändert. Letzteres kann jedoch immer noch nützlich sein. Das folgende Beispiel zeigt, wie POSIX die Verwendung dieses cdBefehls vorstellt :

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

Auf einem POSIX-System meldet dieser Oneliner eine Fehlermeldung für alle Verzeichnisse, in denen Sie nicht zugelassen sind cd. Bei den meisten Gnu / Linux-Distributionen schlägt diese Fehlermeldung jedoch fehl:

find: `cd': No such file or directory

Und hier ist die Antwort auf Ihre Frage: " Warum ist CD kein Programm? ", Von einem der ursprünglichen Unix-Co-Autoren. Bei einer sehr frühen Unix-Implementierung war cd( chdirzu dieser Zeit geschrieben) ein externes Programm. Es hat nur unerwartet aufgehört zu funktionieren, nachdem forkes zum ersten Mal implementiert wurde.

Zitat von Dennis Ritchie :

Inmitten unseres Jubels wurde festgestellt, dass der Befehl chdir (change current directory) nicht mehr funktioniert. Es wurde viel Code gelesen und es wurde ängstlich darüber nachgedacht, wie das Hinzufügen von fork den chdir-Aufruf unterbrochen haben könnte. Schließlich dämmerte die Wahrheit: Im alten System war chdir ein gewöhnlicher Befehl; es hat das aktuelle Verzeichnis des (eindeutigen) Prozesses angepasst, der an das Terminal angehängt ist. Unter dem neuen System hat der Befehl chdir das aktuelle Verzeichnis des zu seiner Ausführung erstellten Prozesses korrekt geändert. Dieser Prozess wurde jedoch sofort beendet und hatte keinerlei Auswirkungen auf die übergeordnete Shell. Chdir musste zu einem speziellen Befehl gemacht werden, der intern in der Shell ausgeführt wurde. Es stellt sich heraus, dass mehrere befehlsähnliche Funktionen dieselbe Eigenschaft haben, zum Beispiel login.

Quelle: Dennis M. Ritchie, „ Die Entwicklung des Unix-Timesharing-Systems “, AT & T Bell Laboratories, Technical Journal 63 (6), Teil 2, Oktober 1984, S. 1577–93

Unix-Version 1 (März 1971) Die Handbuchseite von chdir lautet:

Da ein neuer Prozess erstellt wird, um jeden Befehl auszuführen, wäre chdir ineffektiv, wenn es als normaler Befehl geschrieben würde. Es wird daher von der Shell erkannt und ausgeführt.

jlliagre
quelle
10
... also gibt POSIX anscheinend vor, dass es eine unabhängige cdausführbare Datei geben soll, diese aber nichts tun soll (außer möglicherweise Fehlermeldungen ausgeben, wenn sie mit den falschen Argumenten aufgerufen werden). Seltsam.
Ilmari Karonen
4
Na ja, wenn das stimmt, wäre das nicht die dümmste Sache in POSIX.
Kaz
5
Auf der POSIX-CD-Seite heißt es außerdem: "Da sich CD auf die aktuelle Shell-Ausführungsumgebung auswirkt, wird sie immer als reguläre integrierte Shell bereitgestellt."
Mikel
6
@Kaz, das sind keine ganz anderen Sachen. Sie machen dasselbe, aber nur die eingebaute wirkt sich auf die aktuelle Shell aus.
Juli
13
@Kaz: Bitte nenn mich nicht albern, während ich nur eine Tatsache melde. Sie können POSIX zustimmen oder nicht zustimmen, aber den Messenger nicht abschießen.
Juli
47

Aus der Bash-Einführung ( Was ist eine Shell? ):

Shells bieten auch einen kleinen Satz integrierter Befehle (Builtins), die Funktionen implementieren, die über separate Dienstprogramme nicht oder nur schwer zu erhalten sind. Zum Beispiel cd, break, continueund exec) nicht außerhalb der Schale umgesetzt werden , da sie direkt auf die Schale selbst manipulieren. Die history, getopts, kill, oder pwdbuiltins unter anderem könnte in getrennten Dienstprogramme implementiert werden, aber sie sind bequemer als builtin Befehle zu verwenden. Alle Shell-Buildins werden in den folgenden Abschnitten beschrieben.

cjc
quelle
29

Für Aprilscherz in diesem Jahr habe ich eine eigenständige Version von geschriebencd .

Niemand hat den Witz verstanden. Seufzer.

Jeder, der nicht sicher ist, ob cddies in die Shell integriert werden muss, sollte es herunterladen, erstellen und ausprobieren.

Lesen Sie auch die Manpage. :)

Warren Young
quelle
Wirklich nützlicher Code! :-)
dschulz
6
Schön, dass Sie jemanden sehen, der daran arbeitet, Gnu / Linux POSIX-konformer zu machen. Ihre Implementierung ist nicht nur ein guter Scherz, sondern es fehlt tatsächlich etwas in Linux-Distributionen ...
jlliagre
8
Ich denke, ich werde es nächstes Jahr erneut versuchen, unter Berufung auf das POSIX-Problem. ;)
Warren Young
6 Jahre später: Na, hast du?
Peter A. Schneider
@ PeterA.Schneider: Ich dachte, es sei klar, dass ich Witze mache. Um es klar zu sagen, nein, ich werde nicht wirklich eine Menge Mühe darauf verwenden, dies in Betriebssysteme und OS-ähnliche Projekte wie Cygwin zu integrieren fehlen /bin/cd. Wenn Sie meinen Code nehmen und dies zu Ihrer persönlichen Aufgabe machen möchten, können Sie dies gerne tun.
Warren Young
4

Der cdBefehl in der Shell kann kein separater Prozess sein, da es in Unix keinen Mechanismus zum Ändern des aktuellen Arbeitsverzeichnisses eines anderen Prozesses gibt (nicht einmal des übergeordneten Prozesses).

Wenn dies cdein anderer Prozess wäre, müsste das aktuelle Arbeitsverzeichnis des übergeordneten Elements (Shell) geändert werden, was unter Unix nicht möglich ist. Stattdessen cdist ein spezieller Befehl eingebaut. Die Shell ruft Funktionen auf chdir()und fchdir() ändert ihr eigenes aktuelles Arbeitsverzeichnis.

Hinweis: Der Kernel speichert für jeden Prozess die Inode-Nummer des aktuellen Arbeitsverzeichnisses. Der untergeordnete Prozess erbt ihn cwdvon seinem übergeordneten Prozess .

saurav1405
quelle
0

cd ist ein Shell-Befehl. So einfach wie es ist. Die CD des Mannes sagt alles. Der Befehl cd ändert das Arbeitsverzeichnis für alle Interpreter und (in einer Thread-Umgebung) für alle Threads.


quelle
Weil die Shell die Umgebung ist, die sich um Ihre aktuellen Arbeitsverzeichnisse ($ PDW ...) oder cdable_vars kümmert. Diese integrierte Funktion ist letztendlich die Methode, mit der alle für den Benutzer sichtbaren Befehle das aktuelle Arbeitsverzeichnis ändern sollen. Sie können es auf diese Weise testen: Kompilieren Sie die Bash ohne cd.c und versuchen Sie, ein eigenes CD-Skript zu schreiben, das versucht, alle cdable_vars-Umgebungen zu berücksichtigen. Diese Frage hängt auch eher mit dem Entwickler zusammen. Ich wette, sie könnten Ihnen diese Frage genauer beantworten.
2
Es gibt einen sehr guten technischen Grund, der cdeingebaut ist. Ich würde vorschlagen, dass Sie die bestplatzierten Antworten lesen und überlegen, wie Sie Ihre Antwort verbessern können.
Thorbjørn Ravn Andersen
Die bestplatzierte Antwort war die schlechteste, die ich je gelesen habe! Aber was? Wer bin ich!
3
Aber es beantwortet die Frage warum .
Thorbjørn Ravn Andersen
-1

Ich denke, eine Sache, die in der Antwort der Leute fehlt, ist, dass das aktuelle Verzeichnis eine Umgebungsvariable ist, die jedes Programm ändern kann. Wenn Sie den Befehl 'export' verwenden, um die Liste Ihrer aktuellen Umgebungsvariablen anzuzeigen, haben Sie Folgendes:

declare -x PWD="/home/erfan"

in Ihren Ergebnissen. Mit dem Befehl 'cd' wollen wir also nur diese interne Variable ändern. Ich denke, wenn wir es versuchen, können wir natürlich die PWD-Variable jeder Pty in der Shell ändern. Mögen:

cder    #change current PTY $PWD variable

Aber ich denke, es gibt im Normalfall keine Notwendigkeit. Mit anderen Worten, wir nehmen die Hilfe von bash (oder einer beliebigen Shell) in Anspruch, um die interne Variable zu ändern, die definiert wurde.

Erfankam
quelle
3
Obwohl Bourne-Shells das aktuelle Arbeitsverzeichnis (CWD) als $ PWD verfügbar machen, ist dies nicht der primäre Speicherort. Der tatsächliche Speicherort befindet sich in der prozessbezogenen Struktur des Kernels. Es ist daher falsch zu sagen, dass die CWD "eine Umgebungsvariable ist". Wenn es die Art und Weise gearbeitet , um Ihnen vorschlagen, diese C Zweizeiler würde den Druck ..Pfad, nicht der Weg begann Sie es aus: #include <stdlib.h> int main(void) { chdir(".."); puts(getenv("PWD")); }(C Schalen der CWD als% cwd aussetzen statt, übrigens.)
Warren Young
Fügen Sie Ihrer App weitere Zeilen hinzu. #include <stdlib.h> int main (void) {chdir (".."); puts (getenv ("PWD")); setenv (P PWD, /, 1); puts (getenv ("PWD")); } Was werden wir als Ergebnisse haben?
Erfankam
3
Dadurch wird nur der Wert einer Variablen überschrieben, ohne dass sich dies negativ auf die CWD auswirkt. Dies ist ein besserer Test, um Folgendes zu zeigen: #include <unistd.h> int main(void) { char ac[99]; setenv("PWD", "/", 1); puts(getcwd(ac, sizeof(ac))); }Es wird das Verzeichnis angezeigt, von dem aus Sie das Programm gestartet haben, nicht /.
Warren Young
Ich denke, jeder Prozess hat auch ein Arbeitsverzeichnis und eine Pfadvariable. Also änderst du per chdir einfach dieses Attribut von process. Shell hat dieses Attribut auch und durch cd modifizieren wir dieses Attribut.
Erfankam
4
Nein, ich sage Ihnen, dass $PWDdie Bourne-Shell nur eine Bedeutung hat. Es ist nur eine Möglichkeit für die Shell, Shell-Skripten etwas mitzuteilen, das sie kennt, damit sie nicht aufrufen müssen pwd, um es zu finden. Jedes eigenständige Programm, das vom Wert von $PWDabhängt, ist unzuverlässig.
Warren Young