Digamos que eu faça login em um shell em um sistema unix e comece a digitar comandos. Eu inicialmente começo no diretório inicial do meu usuário ~
. Eu poderia de lá cd
para baixo para o diretório Documents
.
O comando para alterar o diretório de trabalho aqui é muito simples de entender intuitivamente: o nó pai possui uma lista de nós filhos que pode acessar e, presumivelmente, usa uma variante (otimizada) de uma pesquisa para localizar a existência de um nó filho com o nomeie o usuário digitado e o diretório de trabalho é então "alterado" para corresponder a isso - corrija-me se eu estiver errado aí. Pode até ser mais simples que o shell simplesmente "ingenuamente" tente acessar o diretório exatamente de acordo com os desejos do usuário e quando o sistema de arquivos retornar algum tipo de erro, o shell exibirá uma resposta correspondente.
O que me interessa, no entanto, é como o mesmo processo funciona quando navego para cima em um diretório, ou seja, para um pai ou pai de um pai.
Dada a minha localização desconhecida, presumivelmente "cega" Documents
, um dos possivelmente muitos diretórios em toda a árvore do sistema de arquivos com esse nome, como o Unix determina onde devo ser colocado a seguir? Ele faz uma referência pwd
e examina isso? Se sim, como pwd
rastreia o estado de navegação atual?
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:
chdir()
e , a última por . Pode-se vê-los indiretamente em sistemas operacionais Linux ou através do comando no FreeBSD e similares:fchdir()
chroot()
/proc
fstat
Quando a resolução do nome do caminho opera, ela começa em um ou outro desses vnodes referenciados, dependendo se o caminho é relativo ou absoluto. (Existe uma família de
…at()
chamadas de sistema que permite 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.
chdir()
.Se alguém mudar para um nome de caminho relativo, ele manipula a string para anexar esse nome. Se alguém mudar para um nome de caminho absoluto, ele substituirá a string pelo novo nome. Em ambos os casos, ele ajusta a string para remover
.
e..
componentes e perseguir links simbólicos substituindo-os por seus nomes vinculados. ( Aqui está o código do shell Z para isso , por exemplo.)O nome na variável de string interna é rastreado por uma variável de shell chamada
PWD
(oucwd
nos shells C). Isso é exportado convencionalmente como uma variável de ambiente (chamadaPWD
) para programas gerados pelo shell.Esses dois métodos de rastrear coisas são revelados pelas opções
-P
e para os comandos internos do shell e pelas diferenças entre os comandos internos do shell e tanto o comando quanto os comandos internos de coisas como (entre outros) VIM e NeoVIM.-L
cd
pwd
pwd
/bin/pwd
pwd
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); considerando que obter o diretório de trabalho "físico" é uma questão de chamar agetcwd()
função de biblioteca.O funcionamento do
/bin/pwd
programa quando a-L
opção é utilizada é um tanto sutil. Ele não pode confiar no valor daPWD
variável de ambiente que herdou. Afinal, ele não precisa ter sido invocado por um shell e os programas intervenientes podem não ter implementado o mecanismo do shell de fazer com que aPWD
variável de ambiente sempre rastreie o nome do diretório de trabalho. Ou alguém pode fazer o que eu acabei de fazer.Então, o que ele faz é (como diz o padrão POSIX) verificar se o nome fornecido em
PWD
retorna a mesma coisa que o nome.
, como pode ser visto com um rastreamento de chamada do sistema:Como você pode ver: ele só chama
getcwd()
se detectar uma incompatibilidade; e pode ser enganado definindoPWD
uma string que de fato nomeia o mesmo diretório, mas por uma rota diferente.A
getcwd()
função da biblioteca é um assunto por si só. Mas para resumir:..
diretório. Ele parou quando atingiu um loop onde..
era o mesmo que seu diretório de trabalho ou quando houve um erro ao tentar abrir o próximo..
. Isso seria um monte de chamadas de sistema nos bastidores.No entanto, observe que mesmo no FreeBSD e nesses outros sistemas operacionais, o kernel não rastreia o diretório de trabalho com uma string.
Navegar para
..
é novamente um assunto em si. Outro resumo: embora os diretórios convencionalmente (embora, como já mencionado, isso não seja necessário) contenham uma..
estrutura de dados de diretório real no disco, o kernel rastreia o diretório pai de cada diretório vnode e pode, assim, navegar para o..
vnode 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.Aparte
O Windows NT, de fato, faz algo 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 interpretadores de comandos, mas todos os programas Win32) usam para rastrear os nomes de vários diretórios de trabalho (um por unidade), acrescentando ou substituindo-os sempre que 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, pode-se vê-los em subsistemas do tipo Unix rodando no Windows NT, assim como usando os comandos dos interpretadores de
SET
comandos de uma maneira particular.Leitura adicional
pwd
" . The Open Group Base Specifications Problema 7. IEEE 1003.1:2008. O Grupo Aberto. 2016.O kernel não mantém registro de diretórios ou nomes de arquivos; um arquivo ou diretório é representado no kernel por um par inode/dispositivo. Chamadas de sistema como
chdir()
,open()
, etc. recebem um caminho como parâmetro, que pode ser absoluto (ex./etc/passwd
), ou relativo ao diretório atual (exemplos:Documents
,..
). Quando um processo é executadochdir("Documents")
, uma pesquisa é feitaDocuments
no diretório de trabalho atual e o diretório de trabalho do processo é atualizado para se referir a esse diretório. Do ponto de vista do kernel, não há nada de especial no nome "..", é apenas uma convenção no sistema de arquivos que..
se refere ao diretório pai.A
getcwd()
função não é uma chamada de sistema, mas uma função de biblioteca que tem que trabalhar até o diretório raiz, registrando os nomes dos componentes do caminho no caminho.Curiosamente, tradicionalmente
cd ..
é muito mais simples do quepwd
. Os diretórios nomeados..
são colocados explicitamente no sistema de arquivos. O sistema rastreia o dispositivo/inode do diretório atual, então,cd ..
ou mais precisamente, a chamada do sistemachdir("..")
envolve apenas procurar o nome ".." no arquivo pertencente ao inode do diretório atual e alterar o dispositivo/inode do diretório atual para o valor encontrado lá.pwd
(mais precisamente/bin/pwd
) segue..
os links sucessivamente e lê os respectivos diretórios até encontrar o inode de onde veio, montando a lista desses nomes ao contrário até chegar ao diretório raiz (notavelmente não contendo uma..
entrada).Agora, este é o comportamento básico original de baixo nível. Em vez disso , os comandos reais do shell
pwd
dependem de uma variedade de técnicas de armazenamento em cache do nome do caminho atual. Mas, no fundo, é apenas seu inode que é realmente conhecido. Isso implica que, uma vez que os links simbólicos são usados para navegar nos diretórios, as noções de nome do diretório de trabalho atual do shell atual e do sistema/bin/pwd
podem divergir.