Другие ответы - упрощения, каждый из которых представляет только часть истории, и они ошибочны в нескольких моментах.
Существует два способа отслеживания рабочего каталога:
- Для каждого процесса в структуре данных пространства ядра, представляющей этот процесс, ядро хранит две ссылки vnode на vnode рабочего каталога и корневой каталог этого процесса. Первое задание устанавливается с помощью
chdir()
и fchdir()
системных вызовов, последний от chroot()
. Их можно увидеть косвенно в /proc
операционных системах Linux или с помощью fstat
команды на FreeBSD и т. П.% fstat -p $$ | head -n 5
USER CMD PID FD MOUNT INUM MODE SZ | DV R / W
JdeBP zsh 92648 текст / 24958 -r-xr-xr-x 702360 р
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 р
%
Когда выполняется разрешение имени пути, оно начинается с того или другого из указанных ссылочных vnodes, в зависимости от того, является ли путь относительным или абсолютным. (Существует семейство …at()
системных вызовов, которые позволяют начинать разрешение имен с vnode, на который ссылается открытый (каталог) файловый дескриптор в качестве третьей опции.)
В микроядерных Unices структура данных находится в прикладном пространстве, но принцип хранения открытых ссылок на эти каталоги остается прежним.
- Внутри оболочек, таких как оболочки Z, Korn, Bourne Again, C и Almquist, оболочка дополнительно отслеживает рабочий каталог, используя строковые манипуляции с внутренней строковой переменной. Он делает это всякий раз, когда у него есть причина позвонить
chdir()
.Если кто-то меняет относительный путь, он манипулирует строкой, чтобы добавить это имя. Если кто-то изменится на абсолютный путь, он заменит строку новым именем. В обоих случаях корректируется строка для удаления .
и ..
компонентов, а также для поиска символических ссылок, заменяя их связанными именами. ( Вот код оболочки Z для этого , например.)
Имя во внутренней строковой переменной отслеживается переменной оболочки с именем PWD
(или cwd
в оболочках Си). Это обычно экспортируется как переменная окружения (именованная PWD
) в программы, порожденные оболочкой.
Эти два метода отслеживания вещей выявлены с помощью -P
и -L
опций к cd
и pwd
оболочки встроенных команд, а также различия между оболочками встроенных pwd
команд и как /bin/pwd
команды и встроенные pwd
команды вещей , как (среди прочих) ВИМ и НеоВИМ.
% mkdir a; ln -sab
% (cd b; pwd; / bin / pwd; printenv PWD)
/ USR / дома / JdeBP / б
/ USR / дома / JdeBP / а
/ USR / дома / JdeBP / б
% (cd b; pwd -P; / bin / pwd -P)
/ USR / дома / JdeBP / а
/ USR / дома / JdeBP / а
% (cd b; pwd -L; / bin / pwd -L)
/ USR / дома / JdeBP / б
/ USR / дома / JdeBP / б
% (cd -P b; pwd; / bin / pwd; printenv PWD)
/ USR / дома / JdeBP / а
/ USR / дома / JdeBP / а
/ USR / дома / JdeBP / а
% (cd b; PWD = / привет / там / bin / pwd -L)
/ USR / дома / JdeBP / а
%
Как вы можете видеть: получение «логического» рабочего каталога - это вопрос просмотра PWD
переменной оболочки (или переменной среды, если она не является программой оболочки); тогда как получение «физического» рабочего каталога - это вызов getcwd()
функции библиотеки.
Работа /bin/pwd
программы при использовании -L
опции несколько тонкая. Он не может доверять значению PWD
переменной среды, которую он унаследовал. В конце концов, это не должно вызываться оболочкой, и промежуточные программы, возможно, не реализовали механизм оболочки, заставляющий PWD
переменную среды всегда отслеживать имя рабочего каталога. Или кто-то может сделать то, что я сделал только там.
Таким образом, он выполняет (как говорит стандарт POSIX) проверку того, что имя, указанное в, PWD
дает то же самое, что и имя .
, что можно увидеть с помощью трассировки системного вызова:
% ln -sac
% (cd b; ферма / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd')
stat ("/ usr / home / JdeBP / b", { mode = drwxr-xr-x, inode = 120932, размер = 2, blksize = 131072}) = 0 (0x0)
stat (".", {mode = drwxr-xr-x, inode = 120932, размер = 2, blksize = 131072}) = 0 (0x0)
/ USR / дома / JdeBP / б
% (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, размер = 158, blksize = 10240}) = 0 (0x0)
stat (".", {mode = drwxr-xr-x, inode = 120932, размер = 2 , blksize = 131072}) = 0 (0x0)
__getcwd ("/ usr / home / JdeBP / a", 1024) = 0 (0x0)
/ USR / дома / JdeBP / а
% (cd b; PWD = / привет / есть ферма / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd')
stat ("/ hello / there", 0x7fffffffe730) ERR # 2 'Нет такого файла или каталога'
__getcwd ("/ usr / home / JdeBP / a", 1024) = 0 (0x0)
/ USR / дома / JdeBP / а
% (cd b; PWD = / usr / home / JdeBP / c ферма / 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 / дома / JdeBP / с
%
Как видите: он вызывает только в getcwd()
случае обнаружения несоответствия; и его можно одурачить, установив PWD
строку, которая действительно называет тот же каталог, но другим путем.
Функция getcwd()
библиотеки сама по себе является предметом. Но, прежде всего:
Навигация к ..
снова является отдельной темой. Еще один пример: хотя каталоги условно (хотя, как уже упоминалось, это не обязательно) содержат фактические ..
данные в структуре данных каталога на диске, ядро отслеживает родительский каталог каждого vnode каталога и, таким образом, может перейти к ..
vnode любого рабочий каталог. Это несколько усложняется точкой монтирования и измененными корневыми механизмами, которые выходят за рамки этого ответа.
В сторону
Windows NT на самом деле делает то же самое. Для каждого процесса существует один рабочий каталог, установленный SetCurrentDirectory()
вызовом API и отслеживаемый ядром для каждого процесса через (внутренний) дескриптор открытого файла для этого каталога; и есть набор переменных среды, которые программы Win32 (не только интерпретаторы команд, но и все программы Win32) используют для отслеживания имен нескольких рабочих каталогов (по одной на диск), добавляя или перезаписывая их при каждом изменении каталога.
Традиционно, в отличие от случая с операционными системами Unix и Linux, программы Win32 не отображают эти переменные среды пользователям. Однако иногда их можно увидеть в Unix-подобных подсистемах, работающих в Windows NT, а также при использовании команд интерпретаторов SET
команд определенным образом.
дальнейшее чтение