Erro `ls` quando o diretório é excluído

13

Eu tenho duas conchas abertas. O primeiro está no diretório A. No segundo, removo o diretório A e o recrio. Quando eu volto para o primeiro shell e digito ls, a saída é:

ls: cannot open directory .: Stale file handle

Por quê? Eu pensei que o primeiro shell (aquele que permanecesse aberto dentro de um diretório inexistente) "congelaria" enquanto aguardava o próximo comando e não teria "percebido" que o diretório foi excluído e recriado. O shell contém uma referência "mais profunda" ao seu diretório de trabalho atual que não seja a string $PWD?

fonini
fonte
2
Não responde, mas se você simplesmente quiser que a sua concha caia sobre os pés, você pode correr cd $PWD.
dhag
Eu gostaria de entender o que está acontecendo, eu sei que é fácil de obter a volta shell :)
Fonini
Esse diretório está em um servidor NFS? Eu acho que é a única situação em que você recebe identificadores de arquivos obsoletos.
Barmar
O diretório é local. Quando você faz isso no seu sistema, o resultado é diferente?
20915 fonini

Respostas:

17

Um diretório (como qualquer arquivo) não é definido por seu nome. Pense no nome como o endereço do diretório . Quando você move o diretório, ele ainda é o mesmo diretório, assim como se você se mudar para uma casa diferente, você ainda é a mesma pessoa. Se você remover um diretório e criar um novo com o mesmo nome, será um novo diretório, assim como alguém que se muda para a casa onde você morava, não é você.

Cada processo possui um diretório de trabalho . O cdcomando no shell altera o diretório de trabalho atual do shell. O pwdcomando imprime o caminho para o diretório de trabalho atual.

Quando você removeu o diretório A, o que isso fez foi remover a entrada de A em seu diretório pai. O próprio diretório A permaneceu no sistema de arquivos, mas em um estado desanexado, sem nome. Ainda não foi excluído porque estava em uso por um processo, ou seja, o primeiro shell. Quando você alterou o diretório no primeiro shell, o diretório foi finalmente excluído. O mesmo ocorre quando um arquivo é excluído enquanto um processo ainda o abre: a entrada de diretório do arquivo é removida imediatamente e o próprio arquivo é removido quando deixa de ser usado.

Da mesma forma, observe o que acontece quando você move os diretórios.

mkdir one two
touch one/1 two/2
cd one
ls

Em outra concha:

mv one tmp
mv two one
mv tmp two

No primeiro shell:

ls

O arquivo 1está no diretório que foi originalmente chamado onee agora é chamado two. O arquivo 2está no diretório que foi originalmente chamado twoe agora é chamado one.

Precisely Mais precisamente, um caminho, que pode não ser exclusivo se houver links simbólicos ou outras sutilezas.

Gilles 'SO- parar de ser mau'
fonte
Portanto, o ponto principal aqui é que um processo contém o inode de seu diretório de trabalho, não apenas o caminho?
Nacht - Reinstate Monica
1
@Nacht O processo contém um descritor, mas o kernel faz todo o mapeamento (descritor / entradas de tabelas de arquivos / inode). E, de fato, internamente, o kernel não armazena caminhos (porque as coisas interessantes estão no inode, não no caminho). Além disso, um "caminho" é apenas um link para um arquivo ... pode haver vários :)
John WH Smith
oh certo, ele possui um descritor. então bash mantém constantemente um fd do diretório de trabalho? Certamente nem todos os processos têm fds do diretório de trabalho ... eu pensei que eu lembrei fds começando pelo valor de 3 depois de stdin / out / err
Nacht - Reintegrar Monica
2
@Nacht O diretório atual não é um descritor de arquivo, mas funciona como um. O kernel mantém isso para todos os processos. No Linux, você pode vê-lo /proc/<pid>/cwd, o que funciona como /proc/<pid>/fd/<number>. Está CWDna saída de lsof.
Gilles 'SO- stop be evil'
é possível fazer automático cd - && cd -nesse caso?
Vitaly Zdanevich
8

O novo diretório A não é o mesmo que o diretório A. Ele pode ser verificado com o statcomando antes de excluir o antigo e depois de criar um novo, e você verá diferentes números de nós-i.
E eu acho que isso está relacionado a como o kernel funciona. Ele simplesmente controla o número i do diretório atual para cada processo. Portanto, como existem números i diferentes, isso levará a diferentes colisões.

taliezin
fonte
Deve-se notar que um inode é uma estrutura, não um número único. Ele pode ser identificado exclusivamente, mas contém mais informações que seu ID. É isso que o torna mais importante que os links.
John WH Smith
1
@JohnWHSmith Vou excluir esta resposta, pois Gilles one é melhor.
Taliezin 15/05
6
Não há razão para excluir o seu! Se você se sente assim, basta adicionar um aviso à sua resposta, explicando que considera o outro melhor.
terdon
7

Esse é o comportamento esperado. O novo diretório A não é o mesmo que o diretório antigo A, apenas tem o mesmo nome. Portanto, o $ PWD do primeiro terminal ainda se foi, ele não reapareceu magicamente quando você o fez mkdir A.

John
fonte
2
você poderia elaborar sobre 'novo diretório A não é o mesmo que o diretório antigo A'. Quais aspectos do arquivo / diretório são alterados? Isso tem a ver com o número do inode? Desculpe perguntar, mas estou apenas aprendendo sobre isso.
Rahul 14/05
2
@rahul Filosoficamente, o que muda é a sua identidade - um novo diretório foi criado a partir do nada no mesmo local. No nível da implementação, sim, todos os arquivos abertos são identificados pelo inode, e os diretórios antigo e novo terão inodes distintos com diferentes números de inode.
Hobbs 15/05
0

Um diretório, como um arquivo, possui um inode associado a ele:

307% mkdir ABC

308% ls -i 11997708 A 11997709 B 11997710 C

Um inode é uma estrutura de dados que contém informações sobre o diretório ou arquivo. Cada diretório e arquivo tem um. Pense nisso como um endereço (realmente um número de índice).

Se eu estiver em A, número do inode 11997708 e em outro shell (ou no mesmo shell que eu vou fazer), exclua o diretório A, recrie-o e ls o inode:

309% cd A

310% rmdir ../A

311% mkdir ../A

312% ls -i ..

11997720 A 11997709 B 11997710 C

O nó i é diferente, portanto, se ele tentar criar um arquivo no diretório excluído A:

313% tocam nisso

touch: não é possível tocar em 'this': esse arquivo ou diretório não existe

porque o diretório em que estou - não está mais associado ao inode 11997720 - portanto, onde atualmente não estou mais possui um endereço / índice legítimo. Assim, o erro.

user2592248
fonte