Por que eu tenho que sair de um diretório excluído?

18

No meu servidor, tenho uma estrutura de diretórios com algo parecido com isto:

/myproject/code

Eu normalmente tenho uma conexão ssh com o servidor e 'stand' nesse diretório:

root@machine:/myproject/code#

Quando implanto uma nova versão do meu código, o diretório de código é removido, então fico com:

root@machine:/myproject/code# ./run
-bash: ./run: No such file or directory

E a única solução que encontrei é fazer o cd e voltar:

root@machine:/myproject/code# cd ../code
root@machine:/myproject/code# ./run
Running...

Posso evitar isso? É um comportamento um pouco estranho. Se você tem uma boa explicação porque isso acontece, eu apreciaria isso.

    
por Markus Johansson 08.04.2014 / 13:18

7 respostas

25

To me the "cd ../code" is a noop. I'm very interested into hearing why it isn't.

Como arquivos e diretórios são fundamentalmente inodes do sistema de arquivos , não nomes - talvez seja um detalhe de implementação específico do sistema de arquivos tipo, mas é verdade para todos os sistemas ext, então eu vou cumpri-lo aqui.

Quando um novo diretório code é criado, ele é associado a um novo inode e é onde ele está. Não há registro de arquivos e diretórios excluídos anteriormente, portanto, não há meios pelos quais o sistema possa verificar que inode costumava ocupar e, talvez, embaralhar as coisas para que ficasse igual novamente; tal sistema rapidamente se tornaria impraticável, e em qualquer caso, provavelmente não há garantia de que você estaria de volta lá novamente - isso seria indesejável, já que significa que você também pode acidentalmente acabar em outro lugar se um diretório for criado que leva seu inode (atualmente não utilizado).

Não tenho certeza se essa última possibilidade existe, ou se o inode do diretório excluído atualmente atribuído ao seu diretório de trabalho atual é rastreado, de forma que nada será atribuído a ele durante o período, etc.

    
por 08.04.2014 / 14:26
14

Seu shell não sempre faz um cd no caminho em que estava durante o último comando, antes de executar o próximo comando.

Você excluiu o diretório atual e criou um diretório com o mesmo nome, que não é o mesmo diretório, apenas algo com o mesmo nome / caminho.

Navegadores de arquivos como o Nautilus e o Windows Explorer normalmente "sobem" na árvore de diretórios se um diretório for excluído em um sistema de arquivos local. No entanto, isso nem sempre é verdadeiro para sistemas de arquivos em rede; nesse caso, às vezes, a exclusão não é notada e o reaparecimento pode fazer com que você acabe no novo diretório.

Um shell pode cd no diretório atual antes de executar o próximo comando, não tenho conhecimento de nenhum que faça (ou pode ser configurado para fazer isso).

    
por 08.04.2014 / 13:58
4

Na maioria dos sistemas UNIX, o "diretório atual" de um processo é armazenado no kernel como um descritor de arquivo que aponta para esse diretório. O kernel na verdade não armazena o caminho do diretório atual: essa informação é rastreada pelo seu shell.

Um objeto do sistema de arquivos (diretório ou ) é destruído apenas quando todos os links do sistema de arquivos não existem, e não há descritores apontando para esse objeto.

Portanto, se um diretório for removido enquanto ainda houver um processo mantendo-o como seu diretório de trabalho atual, o cwd do processo impedirá que o diretório seja realmente excluído. Os links do sistema de arquivos que ancoram o diretório (sua entrada no diretório pai e todo o seu conteúdo) desaparecerão, mas o diretório em si continuará existindo como uma espécie de "zumbi". Enquanto isso, você pode criar um novo diretório no mesmo local que o antigo, que é um objeto do sistema de arquivos completamente diferente, mas que compartilha o mesmo caminho.

Assim, quando você faz cd ../code (ou, em muitos shells, cd . ), você está realmente percorrendo a hierarquia do sistema de arquivos e indo para o diretório novo que reside no endereço antigo.

Por analogia, remover um diretório seria como mover vigorosamente uma casa para o depósito de lixo (quebrando os laços com o endereço anterior). Se ainda houvesse alguém morando lá (usando como cwd ), eles teriam que sair antes que a casa pudesse ser demolida. Enquanto isso, uma casa nova poderia ser construída no endereço antigo.

    
por 09.04.2014 / 06:24
0

@As razões aprovadas pelo Anthon, por que isso acontece
Como solução você pode usar alias , como exemplo:

alias 1234='PROJECT='pwd'; cd $PROJECT ; ./run'

aliases para o bash são mantidos em ~ / .bashrc

    
por 08.04.2014 / 14:29
0

Confirmando O diretório de trabalho atual é baseado no número de inode, não o que você procurava para chegar lá. Como você está usando o bash, você pode usar o $ PWD da seguinte forma para o cd no novo diretório com o mesmo nome:

cd $ PWD

Para ilustrar, criei um comando de implantação simulado:

set -x
cd ~/tmp
rm -rf code
mkdir code
echo echo hello from $* > code/run
chmod +x code/run

Criou a primeira implantação, escreveu o cd para codificar e, em seguida, verificou o conteúdo com ls -lai para que você possa ver os inodes:

ianh@abe:~/tmp$ ./,deploy first
++ cd /home/ianh/tmp
++ rm -rf code
++ mkdir code
++ echo echo hello from first
++ chmod +x code/run
ianh@abe:~/tmp$ cd code
ianh@abe:~/tmp/code$ ls -lai
total 12
22945913 drwxr-xr-x  2 ianh ianh 4096 Apr  9 23:12 .
22937618 drwxrwxr-x 14 ianh ianh 4096 Apr  9 23:12 ..
22939455 -rwxr-xr-x  1 ianh ianh   22 Apr  9 23:12 run

Agora execute o segundo deploy

ianh@abe:~/tmp/code$ ../,deploy 2nd
++ cd /home/ianh/tmp
++ rm -rf code
++ mkdir code
++ echo echo hello from 2nd
++ chmod +x code/run

E verifique o conteúdo do diretório ... agora não há nada no diretório! nem mesmo '.' e '..'! A partir disso você pode ver que bash não está usando a entrada de diretório '..' quando você executa cd .. desde que '..' não existe mais - Eu presumo que seja parte de sua manipulação $ PWD. Alguns shell / shell mais antigos não suportam cd .. nesta situação, você tem que fazer um cd para um caminho absoluto primeiro.

ianh@abe:~/tmp/code$ ls -lai
total 0

Cd para $PWD e tente novamente:

ianh@abe:~/tmp/code$ cd $PWD
ianh@abe:~/tmp/code$ ls -lai
total 12
22945914 drwxr-xr-x  2 ianh ianh 4096 Apr  9 23:12 .
22937618 drwxrwxr-x 14 ianh ianh 4096 Apr  9 23:12 ..
22939455 -rwxr-xr-x  1 ianh ianh   20 Apr  9 23:12 run
ianh@abe:~/tmp/code$ ./run
hello from 2nd

Observe como o inode do diretório atual (.) mudou?

Se o script de implantação movesse o diretório antigo para outro nome, por exemplo, mv code code.$$ no script de implantação acima, então ./run funcionaria, mas até você usar cd $PWD estar executando o código antigo , não o novo.

ianh@abe:~/tmp/code$ ./run
hello from 2nd
ianh@abe:~/tmp/code$ ../,deploy 3rd
++ cd /home/ianh/tmp
++ '[' -d code ']'
++ mv code code.9629
++ mkdir code
++ echo echo hello from 3rd
++ chmod +x code/run
ianh@abe:~/tmp/code$ ./run
hello from 2nd
ianh@abe:~/tmp/code$ cd $PWD
ianh@abe:~/tmp/code$ ./run
hello from 3rd

A implantação usando capistrano tem o mesmo problema (eles têm um link simbólico do nome atual para o release atual), então eu uso aliases para cd nas áreas de produção / preparação, bem como configure RAIL_ENV apropriadamente:

alias cdp='export RAILS_ENV=production; echo RAILS_ENV=$RAILS_ENV ; cd /var/www/www.example.com/current'
alias cds='export RAILS_ENV=staging; echo RAILS_ENV=$RAILS_ENV ; cd /var/www/staging.example.com/current'
    
por 09.04.2014 / 15:45
0

What I assume is that the path is what identifies the directory.

O caminho para algo é como você chega lá, não a coisa em si. O caminho para a sua cama pode ser através do seu quarto, mas quando você estiver na cama, se alguém o pegar e levar para fora, você não estará mais no seu quarto.

    
por 09.04.2014 / 17:35
0

Não é uma resposta independente, mas eu tenho um ponto adicional, que a margem de comentários era pequena demais para conter.

Para entender melhor a ideia de que um diretório nos sistemas de arquivos relevantes é mais do que um caminho, tente mover o diretório de trabalho atual de outro processo: em um shell, inicie uma sessão interativa do Python:

$ python
>> import os
>> os.getcwd()
'/home/you/hocus'

Em seguida, vá para outro shell e mova esse diretório:

$ cd /home/you
$ mv hocus pocus

Voltar para o original:

$ python
>> import os
>> os.getcwd()
'/home/you/hocus'
>> os.getcwd()
'/home/you/pocus'
    
por 20.09.2018 / 15:19