Inne odpowiedzi są uproszczeniami, z których każda przedstawia tylko fragmenty historii i są błędne w kilku punktach.
Istnieją dwa sposoby śledzenia katalogu roboczego:
- Dla każdego procesu w strukturze danych przestrzeni jądra, która reprezentuje ten proces, jądro przechowuje dwa odwołania vnode do vnodes katalogu roboczego i katalogu głównego dla tego procesu. Pierwsze odniesienie jest ustawione przez wywołania systemowe
chdir()i fchdir(), drugie przez chroot(). Można je zobaczyć pośrednio w /procsystemach operacyjnych Linux lub za pomocą fstatpolecenia na FreeBSD i tym podobnych:% fstat -p $$ | head -n 5
UŻYTKOWNIK CMD PID FD MOUNT INUM MODE 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
%
Kiedy działa rozpoznawanie nazw ścieżek, zaczyna się od jednego lub drugiego z tych przywoływanych vnodes, w zależności od tego, czy ścieżka jest względna czy bezwzględna. (Istnieje rodzina …at()wywołań systemowych, które umożliwiają rozpoznawanie nazw ścieżek rozpoczynające się od vnode, do którego odwołuje się deskryptor pliku otwartego (katalogu) jako trzecia opcja).
W mikrojądrach Unices struktura danych znajduje się w przestrzeni aplikacji, ale zasada utrzymywania otwartych odniesień do tych katalogów pozostaje taka sama.
- Wewnętrznie, w powłokach takich jak powłoka Z, Korn, Bourne Again, C i Almquist, powłoka dodatkowo śledzi katalog roboczy za pomocą manipulacji ciągiem wewnętrznej zmiennej łańcuchowej. Robi to za każdym razem, gdy ma powód do połączenia
chdir().Jeśli ktoś zmieni się na względną nazwę ścieżki, manipuluje ciągiem, aby dodać tę nazwę. Jeśli ktoś zmieni bezwzględną nazwę ścieżki, zastępuje ciąg nową nazwą. W obu przypadkach dostosowuje ciąg do usunięcia .i ..komponentów oraz do ścigania dowiązań symbolicznych, zastępując je nazwami połączonymi z nimi. ( Oto przykładowy kod powłoki Z. )
Nazwa w wewnętrznej zmiennej łańcucha jest śledzona przez zmienną powłoki o nazwie PWD(lub cwdw powłokach C). Jest to konwencjonalnie eksportowane jako zmienna środowiskowa (o nazwie PWD) do programów spawnowanych przez powłokę.
Te dwie metody śledzenia rzeczy są ujawniane przez -Pi -Lopcje do cdi pwdpowłoki wbudowanych komend i różnicami między muszli wbudowanych pwdpoleceń i zarówno /bin/pwdpolecenia i wbudowanych pwdpoleceń rzeczy jak (między innymi) VIM i 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 = / hello / there / bin / pwd -L)
/ usr / home / JdeBP / a
%
Jak widać: uzyskanie „logicznego” katalogu roboczego polega na spojrzeniu na PWDzmienną powłoki (lub zmienną środowiskową, jeśli nie jest to program powłoki); podczas gdy uzyskanie „fizycznego” katalogu roboczego jest kwestią wywołania getcwd()funkcji biblioteki.
Działanie /bin/pwdprogramu, gdy -Lużywana jest opcja, jest nieco subtelne. Nie może ufać wartości PWDodziedziczonej zmiennej środowiskowej. W końcu nie musiała być wywoływana przez powłokę, a interweniujące programy mogły nie wdrożyć mechanizmu powłoki polegającego na tym, że PWDzmienna środowiskowa zawsze śledzi nazwę katalogu roboczego. Albo ktoś może zrobić to, co właśnie tam zrobiłem.
Więc to, co robi (jak mówi standard POSIX), sprawdza, czy nazwa podana w PWDdaje to samo co nazwa ., co można zobaczyć za pomocą śledzenia wywołania systemowego:
% 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, 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 truss / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd')
stat ("/ usr / local / etc" , {mode = drwxr-xr-x, i-węzeł = 14835, rozmiar = 158, rozmiar blks = 10240}) = 0 (0x0)
stat (".", {mode = drwxr-xr-x, i-węzeł = 120932, rozmiar = 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 „Brak takiego pliku lub katalogu”
__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 , rozmiar = 2, rozmiar blks = 131072}) = 0 (0x0)
/ usr / home / JdeBP / c
%
Jak widać: wywołuje tylko getcwd()wtedy, gdy wykryje niezgodność; i można go oszukać, ustawiając PWDciąg znaków, który rzeczywiście nazywa ten sam katalog, ale inną drogą.
Funkcja getcwd()biblioteczna jest odrębnym przedmiotem. Ale aby to zrobić:
Nawigacja do ..jest znowu osobnym tematem. Kolejna zasada: chociaż katalogi konwencjonalnie (choć, jak już wspomniano, nie jest to wymagane) zawierają rzeczywistą ..strukturę danych katalogu na dysku, jądro śledzi katalog macierzysty każdego vnode katalogu i może w ten sposób nawigować do ..vnode dowolnego katalog roboczy. Jest to nieco skomplikowane przez punkt montowania i zmienione mechanizmy rootowania, które są poza zakresem tej odpowiedzi.
Na bok
Windows NT faktycznie robi podobne rzeczy. Istnieje jeden katalog roboczy na proces, ustawiony przez SetCurrentDirectory()wywołanie API i śledzony na proces przez jądro za pomocą (wewnętrznego) dojścia do otwartego pliku do tego katalogu; i istnieje zestaw zmiennych środowiskowych, które programy Win32 (nie tylko interpreter poleceń, ale wszystkie programy Win32) używają do śledzenia nazw wielu działających katalogów (jednego na dysk), dołączając je lub zastępując przy każdej zmianie katalogu.
Konwencjonalnie, w przeciwieństwie do systemów operacyjnych Unix i Linux, programy Win32 nie wyświetlają tych zmiennych środowiskowych użytkownikom. Czasem można je zobaczyć w podsystemach uniksopodobnych działających w systemie Windows NT, a także przy użyciu poleceń interpretera SETpoleceń w określony sposób.
Dalsza lektura