As outras respostas são simplificações excessivas, cada uma apresentando apenas partes da história, e estão erradas em alguns pontos.
Há duas maneiras pelas quais o diretório de trabalho é rastreado:
- Para cada processo, na estrutura de dados do espaço do kernel que representa esse processo, o kernel armazena duas referências de vnode aos vnodes do diretório de trabalho e o diretório raiz desse processo. A referência anterior é definida pelas chamadas
chdir()
e do fchdir()
sistema, e a última por chroot()
. Pode-se vê-los indiretamente nos /proc
sistemas operacionais Linux ou através do fstat
comando no FreeBSD e similares:% fstat -p $$ | cabeça -n 5
USUÁRIO CMD PID FD MOUNT INUM MODO 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
%
Quando a resolução do nome do caminho opera, ela começa em um ou outro daqueles vnodes referenciados, dependendo se o caminho é relativo ou absoluto. (Há uma família de …at()
chamadas de sistema que permitem que a resolução do nome do caminho comece no vnode referenciado por um descritor de arquivo aberto (diretório) como uma terceira opção.)
No microkernel Unices, a estrutura de dados está no espaço do aplicativo, mas o princípio de manter referências abertas a esses diretórios permanece o mesmo.
- Internamente, dentro de shells como o shell Z, Korn, Bourne Again, C e Almquist, o shell também acompanha o diretório de trabalho usando a manipulação de strings de uma variável interna de strings. Faz isso sempre que houver motivo para ligar
chdir()
.Se alguém mudar para um nome de caminho relativo, ele manipula a string para acrescentar esse nome. Se alguém mudar para um nome de caminho absoluto, ele substituirá a sequência pelo novo nome. Nos dois casos, ajusta a sequência para remover .
e ..
componentes e perseguir links simbólicos, substituindo-os pelos nomes vinculados. ( Aqui está o código do shell Z para isso , por exemplo).
O nome na variável de cadeia interna é rastreado por uma variável de shell denominada PWD
(ou cwd
nos shells C). Isso é convencionalmente exportado como uma variável de ambiente (nomeada PWD
) para programas gerados pelo shell.
Estes dois métodos de coisas rastreamento são reveladas pelos -P
e -L
opções para o cd
e pwd
shell built-in comandos e pelas diferenças entre as conchas Built-in pwd
comandos e tanto o /bin/pwd
comando e o built-in pwd
comandos de coisas como (entre outros) VIM e 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 = / olá / lá / bin / pwd -L)
/ usr / home / JdeBP / a
%
Como você pode ver: obter o diretório de trabalho "lógico" é uma questão de olhar para a PWD
variável shell (ou variável de ambiente, se não for o programa shell); enquanto que obter o diretório de trabalho "físico" é uma questão de chamar a getcwd()
função de biblioteca.
A operação do /bin/pwd
programa quando a -L
opção é usada é um pouco sutil. Ele não pode confiar no valor da PWD
variável de ambiente que herdou. Afinal, ele não precisa ter sido chamado por um shell e os programas intervenientes podem não ter implementado o mecanismo do shell de tornar a PWD
variável de ambiente sempre rastrear o nome do diretório de trabalho. Ou alguém pode fazer o que eu fiz lá.
Então, o que ele faz é (como o padrão POSIX diz) verificar se o nome fornecido PWD
produz a mesma coisa que o nome .
, como pode ser visto em um rastreamento de chamada do sistema:
% 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, tamanho = 2, tamanho do bloco = 131072}) = 0 (0x0)
stat (".", {mode = drwxr-xr-x, inode = 120932, tamanho = 2, tamanho do bloco = 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, tamanho = 158, tamanho do bloco = 10240}) = 0 (0x0)
stat (".", {mode = drwxr-xr-x, inode = 120932, size = 2 , tamanho do bloco = 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", 0x7fffffffefe730) ERR # 2 'Não
existe esse arquivo ou diretório' __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, tamanho = 2, tamanho do bloco = 131072}) = 0 (0x0)
stat (". ", {Mode = drwxr-xr-x, inode = 120932 , tamanho = 2, tamanho do bloco = 131072}) = 0 (0x0)
/ usr / home / JdeBP / c
%
Como você pode ver: ele só chama getcwd()
se detectar uma incompatibilidade; e pode ser enganado definindo PWD
uma cadeia que de fato nomeia o mesmo diretório, mas por uma rota diferente.
A getcwd()
função de biblioteca é um assunto em si. Mas précis:
Navegar para ..
é novamente um assunto em si. Outra característica: embora os diretórios convencionalmente (embora, como já mencionado, isso não seja necessário) contenham um real ..
na estrutura de dados do diretório no disco, o kernel rastreia o diretório pai de cada diretório do próprio nó e, portanto, pode navegar para o ..
nó de qualquer diretório de trabalho. Isso é um pouco complicado pelo ponto de montagem e pelos mecanismos raiz alterados, que estão além do escopo desta resposta.
a parte, de lado
Windows NT, de fato, faz uma coisa semelhante. Há um único diretório de trabalho por processo, definido pela SetCurrentDirectory()
chamada da API e rastreado por processo pelo kernel por meio de um identificador de arquivo aberto (interno) para esse diretório; e há um conjunto de variáveis de ambiente que os programas Win32 (não apenas os intérpretes de comando, mas todos os programas Win32) usam para rastrear os nomes de vários diretórios de trabalho (um por unidade), anexando-os ou substituindo-os sempre que eles mudam de diretório.
Convencionalmente, diferentemente do caso dos sistemas operacionais Unix e Linux, os programas Win32 não exibem essas variáveis de ambiente para os usuários. Às vezes, é possível vê-los em subsistemas do tipo Unix em execução no Windows NT, bem como usando os comandos dos intérpretes de SET
comando de uma maneira específica.
Leitura adicional