Die anderen Antworten sind Übervereinfachungen, die jeweils nur Teile der Geschichte darstellen und in einigen Punkten falsch sind.
Es gibt zwei Möglichkeiten, um das Arbeitsverzeichnis zu verfolgen:
- Für jeden Prozess speichert der Kernel in der Kernel-Space-Datenstruktur, die diesen Prozess darstellt, zwei V-Knoten-Verweise auf die V-Knoten des Arbeitsverzeichnisses und des Stammverzeichnisses für diesen Prozess. Die erstere Referenz wird durch die Menge
chdir()
und die fchdir()
Systemaufrufe, wobei letztere durch chroot()
. Man kann sie indirekt /proc
unter Linux-Betriebssystemen oder über den fstat
Befehl unter FreeBSD und dergleichen sehen:% fstat -p $$ | head -n 5
BENUTZER CMD PID FD MONTAGE INUM MODUS SZ | DV R / W
JdeBP zsh 92648 text / 24958 -r-xr-xr-x 702360 r
JdeBP zsh 92648 ctty / dev 148 crw - w ---- pts / 4 rw
JdeBP zsh 92648 wd / usr / home / JdeBP 4 drwxr-xr-x 124 r
JdeBP zsh 92648 root / 4 drwxr-xr-x 35 r
%
Wenn die Pfadnamenauflösung ausgeführt wird, beginnt sie bei dem einen oder anderen dieser referenzierten Knoten, je nachdem, ob der Pfad relativ oder absolut ist. (Es gibt eine …at()
Reihe von Systemaufrufen, mit denen die Pfadnamenauflösung an dem Knoten beginnen kann, auf den ein offener (Verzeichnis-) Dateideskriptor als dritte Option verweist.)
In Microkernel Unices befindet sich die Datenstruktur im Anwendungsbereich, aber das Prinzip, Verweise auf diese Verzeichnisse offen zu halten, bleibt dasselbe.
- Intern verfolgt die Shell in Shells wie der Z-, Korn-, Bourne Again-, C- und Almquist-Shell außerdem das Arbeitsverzeichnis mithilfe der Zeichenfolgenmanipulation einer internen Zeichenfolgenvariablen. Dies geschieht immer dann, wenn es Grund zum Aufrufen hat
chdir()
.Wenn ein relativer Pfadname geändert wird, wird die Zeichenfolge bearbeitet, um diesen Namen anzufügen. Wenn ein absoluter Pfadname geändert wird, wird die Zeichenfolge durch den neuen Namen ersetzt. In beiden Fällen wird die Zeichenfolge angepasst, um Komponenten zu entfernen .
und ..
symbolische Verknüpfungen aufzuspüren, indem sie durch ihre verknüpften Namen ersetzt werden. ( Hier ist zum Beispiel der Code der Z-Shell .)
Der Name in der internen Zeichenfolgenvariablen wird von einer Shell-Variablen namens PWD
(oder cwd
in den C-Shells) verfolgt. Dies wird herkömmlicherweise als Umgebungsvariable (benannt PWD
) in Programme exportiert, die von der Shell erzeugt werden.
Diese beiden Methoden der Verfolgung Dinge enthüllt werden von den -P
und -L
Optionen auf die cd
und pwd
Shell integrierte Befehle, und durch die Unterschiede zwischen den Schalen built-in pwd
Befehle und sowohl den /bin/pwd
Befehl und die eingebaute in pwd
Befehle von Dingen wie (unter anderem) VIM und NeoVIM.
% mkdir a; ln -sab
% (cd b; pwd; / bin / pwd; Druck-PWD)
/ usr / home / JdeBP / b
/ usr / home / JdeBP / a
/ usr / home / JdeBP / b
% (cd b; pwd -P; / bin / pwd -P)
/ usr / home / JdeBP / a
/ usr / home / JdeBP / a
% (cd b; pwd -L; / bin / pwd -L)
/ usr / home / JdeBP / b
/ usr / home / JdeBP / b
% (cd -P b; pwd; / bin / pwd; Druck-PWD)
/ usr / home / JdeBP / a
/ usr / home / JdeBP / a
/ usr / home / JdeBP / a
% (cd b; PWD = / hallo / dort / bin / pwd -L)
/ usr / home / JdeBP / a
%
Wie Sie sehen können: Um das "logische" Arbeitsverzeichnis zu erhalten, müssen Sie sich die PWD
Shell-Variable (oder die Umgebungsvariable, falls es sich nicht um das Shell-Programm handelt) ansehen. Um das "physische" Arbeitsverzeichnis zu erhalten, muss die getcwd()
Bibliotheksfunktion aufgerufen werden.
Die Bedienung des /bin/pwd
Programms bei Verwendung der -L
Option ist etwas subtil. Es kann dem Wert der PWD
Umgebungsvariablen, die es geerbt hat, nicht vertrauen . Schließlich muss es nicht von einer Shell aufgerufen worden sein, und möglicherweise haben intervenierende Programme den Mechanismus der Shell, mit dem die PWD
Umgebungsvariable immer den Namen des Arbeitsverzeichnisses verfolgt, nicht implementiert . Oder jemand kann das tun, was ich gerade dort getan habe.
Es wird also (wie der POSIX-Standard sagt) überprüft, ob der in angegebene Name PWD
das Gleiche ergibt wie der Name .
, wie bei einem Systemaufruf-Trace zu sehen ist:
% ln -sac
% (cd b; Fachwerk / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd')
stat ("/ usr / home / JdeBP / b", { mode = drwxr-xr-x, inode = 120932, size = 2, blksize = 131072}) = 0 (0x0)
stat (".", {mode = drwxr-xr-x, inode = 120932, size = 2, blksize = 131072}) = 0 (0x0)
/ usr / home / JdeBP / b
% (cd b; PWD = / usr / local / etc Fachwerk / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd')
stat ("/ usr / local / etc" , {mode = drwxr-xr-x, inode = 14835, size = 158, blksize = 10240}) = 0 (0x0)
stat (".", {mode = drwxr-xr-x, inode = 120932, size = 2 , blksize = 131072}) = 0 (0x0)
__getcwd ("/ usr / home / JdeBP / a", 1024) = 0 (0x0)
/ usr / home / JdeBP / a
% (cd b; PWD = / hello / there truss / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd')
stat ("/ hello / there", 0x7fffffffe730) ERR # 2 'Keine solche Datei oder kein solches Verzeichnis'
__getcwd ("/ usr / home / JdeBP / a", 1024) = 0 (0x0)
/ usr / home / JdeBP / a
% (cd b; PWD = / usr / home / JdeBP / c truss / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd')
stat ("/ usr / home / JdeBP / c ", {mode = drwxr-xr-x, inode = 120932, size = 2, blksize = 131072}) = 0 (0x0)
stat (". ", {Mode = drwxr-xr-x, inode = 120932 , size = 2, blksize = 131072}) = 0 (0x0)
/ usr / home / JdeBP / c
%
Wie Sie sehen können: Es ruft nur auf, getcwd()
wenn es eine Nichtübereinstimmung feststellt. und es kann getäuscht werden, indem PWD
eine Zeichenfolge festgelegt wird, die zwar dasselbe Verzeichnis benennt, jedoch auf einem anderen Weg.
Die getcwd()
Bibliotheksfunktion ist ein eigenständiges Fach. Aber vorab:
Das Navigieren zu ..
ist wieder ein eigenständiges Thema. Eine weitere Voraussetzung: Obwohl Verzeichnisse herkömmlicherweise (obwohl, wie bereits erwähnt, dies nicht erforderlich ist) eine tatsächliche ..
Verzeichnisdatenstruktur auf der ..
Festplatte enthalten , verfolgt der Kernel das übergeordnete Verzeichnis jedes Verzeichnisknotens selbst und kann so zum Knoten eines beliebigen Verzeichnisknotens navigieren Arbeitsverzeichnis. Dies wird durch den Einhängepunkt und geänderte Root-Mechanismen etwas kompliziert, die den Rahmen dieser Antwort sprengen.
Beiseite
Windows NT macht in der Tat eine ähnliche Sache. Es gibt ein einziges Arbeitsverzeichnis pro Prozess, das vom SetCurrentDirectory()
API-Aufruf festgelegt und vom Kernel über ein (internes) offenes Dateihandle zu diesem Verzeichnis pro Prozess verfolgt wird. Außerdem gibt es eine Reihe von Umgebungsvariablen, mit denen Win32-Programme (nicht nur die Befehlsinterpreter, sondern alle Win32-Programme) die Namen mehrerer Arbeitsverzeichnisse (eines pro Laufwerk) verfolgen und diese bei jedem Verzeichniswechsel anhängen oder überschreiben.
Im Gegensatz zu Unix- und Linux-Betriebssystemen zeigen Win32-Programme Benutzern diese Umgebungsvariablen normalerweise nicht an. Man kann sie jedoch manchmal in Unix-ähnlichen Subsystemen sehen, die unter Windows NT ausgeführt werden, oder indem man die SET
Befehle der Befehlsinterpreter auf eine bestimmte Weise verwendet.
Weitere Lektüre