Les autres réponses sont des simplifications excessives, chacune ne présentant que des parties de l'histoire, et elles sont erronées sur quelques points.
Il existe deux façons de suivre le répertoire de travail:
- Pour chaque processus, dans la structure de données de l'espace noyau qui représente ce processus, le noyau stocke deux références vnode aux vnodes du répertoire de travail et au répertoire racine de ce processus. La première référence est définie par les appels système
chdir()
et fchdir()
, la seconde par chroot()
. On peut les voir indirectement dans /proc
sur les systèmes d'exploitation Linux ou via la fstat
commande sur FreeBSD et similaires:% fstat -p $$ | head -n 5
UTILISATEUR CMD PID FD MONTAGE MODE INUM SZ | DV R / W
JdeBP zsh 92648 texte / 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
%
Lorsque la résolution de chemin d'accès fonctionne, elle commence à l'un ou l'autre de ces vnodes référencés, selon que le chemin est relatif ou absolu. (Il existe une famille d' …at()
appels système qui permettent à la résolution de chemin d'accès de commencer au niveau du vnode référencé par un descripteur de fichier ouvert (répertoire) comme troisième option.)
Dans les micro-noyaux, la structure des données se trouve dans l'espace d'application, mais le principe de la tenue de références ouvertes à ces répertoires reste le même.
- En interne, dans des shells tels que le shell Z, Korn, Bourne Again, C et Almquist, le shell garde en outre la trace du répertoire de travail en utilisant la manipulation de chaîne d'une variable de chaîne interne. Il le fait chaque fois qu'il a un appel à faire
chdir()
.Si l'on change pour un chemin d'accès relatif, il manipule la chaîne pour ajouter ce nom. Si l'on passe à un nom de chemin absolu, il remplace la chaîne par le nouveau nom. Dans les deux cas, il ajuste la chaîne à supprimer .
et les ..
composants et à chasser les liens symboliques en les remplaçant par leurs noms liés. ( Voici le code du shell Z pour cela , par exemple.)
Le nom dans la variable de chaîne interne est suivi par une variable shell nommée PWD
(ou cwd
dans les shells C). Ceci est traditionnellement exporté en tant que variable d'environnement (nommée PWD
) vers des programmes générés par le shell.
Ces deux méthodes de choses de suivi sont révélées par les -P
et -L
options à la cd
et pwd
shell commandes intégrées, et par les différences entre les coquilles intégrées pwd
commandes et à la fois la /bin/pwd
commande et le haut- pwd
commandes des choses comme (entre autres) VIM et NeoVIM.
% mkdir a; ln -sab
% (cd b; pwd; / bin / pwd; printenv 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; printenv PWD)
/ usr / home / JdeBP / a
/ usr / home / JdeBP / a
/ usr / home / JdeBP / a
% (cd b; PWD = / bonjour / là / bin / pwd -L)
/ usr / home / JdeBP / a
%
Comme vous pouvez le voir: obtenir le répertoire de travail "logique" consiste à regarder la PWD
variable shell (ou la variable d'environnement si l'on n'est pas le programme shell); tandis que l'obtention du répertoire de travail "physique" consiste à appeler la getcwd()
fonction de bibliothèque.
Le fonctionnement du /bin/pwd
programme lorsque l' -L
option est utilisée est quelque peu subtil. Il ne peut pas faire confiance à la valeur de la PWD
variable d'environnement dont il a hérité. Après tout, il n'a pas besoin d'être invoqué par un shell et les programmes intermédiaires peuvent ne pas avoir implémenté le mécanisme du shell pour que la PWD
variable d'environnement suive toujours le nom du répertoire de travail. Ou quelqu'un peut faire ce que j'ai fait juste là.
Donc, ce qu'il fait est (comme le dit la norme POSIX) de vérifier que le nom donné en PWD
donne la même chose que le nom .
, comme on peut le voir avec une trace d'appel système:
% ln -sac
% (cd b; truss / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd')
stat ("/ usr / home / JdeBP / b", { mode = drwxr-xr-x, inode = 120932, taille = 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 truss / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd')
stat ("/ usr / local / etc" , {mode = drwxr-xr-x, inode = 14835, taille = 158, blksize = 10240}) = 0 (0x0)
stat (".", {mode = drwxr-xr-x, inode = 120932, taille = 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 'Aucun fichier ou répertoire de ce type'
__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, taille = 2, blksize = 131072}) = 0 (0x0)
stat (". ", {Mode = drwxr-xr-x, inode = 120932 , taille = 2, blksize = 131072}) = 0 (0x0)
/ usr / home / JdeBP / c
%
Comme vous pouvez le voir: il n'appelle que getcwd()
s'il détecte un décalage; et il peut être trompé en définissant PWD
une chaîne qui nomme effectivement le même répertoire, mais par une route différente.
La getcwd()
fonction de bibliothèque est un sujet à part entière. Mais pour précis:
Naviguer vers ..
est à nouveau un sujet à part entière. Un autre précis: Bien que les répertoires conventionnellement (bien que, comme cela a déjà été mentionné, cela ne soit pas requis) contiennent un réel ..
dans la structure de données du répertoire sur le disque, le noyau suit le répertoire parent de chaque répertoire vnode lui-même et peut ainsi naviguer vers le ..
vnode de n'importe quel directeur de travail. Ceci est quelque peu compliqué par le point de montage et les mécanismes racine modifiés, qui dépassent le cadre de cette réponse.
De côté
Windows NT fait en fait une chose similaire. Il existe un seul répertoire de travail par processus, défini par l' SetCurrentDirectory()
appel d'API et suivi par processus par le noyau via un descripteur de fichier ouvert (interne) vers ce répertoire; et il existe un ensemble de variables d'environnement que les programmes Win32 (pas seulement les interpréteurs de commandes, mais tous les programmes Win32) utilisent pour suivre les noms de plusieurs répertoires de travail (un par lecteur), en les ajoutant ou en les écrasant chaque fois qu'ils changent de répertoire.
Classiquement, contrairement au cas des systèmes d'exploitation Unix et Linux, les programmes Win32 n'affiche pas ces variables d'environnement pour les utilisateurs. On peut parfois les voir dans des sous-systèmes de type Unix fonctionnant sous Windows NT, ainsi qu'en utilisant les commandes des interprètes de SET
commande d'une manière particulière.
Lectures complémentaires