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

19

No meu servidor, eu tenho uma estrutura de diretórios parecida com esta:

/myproject/code

Normalmente, tenho uma conexão ssh com o servidor e 'fica' 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 é entrar e sair de CD:

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

Posso evitar isso? É um comportamento um tanto estranho. Se você tem uma boa explicação sobre o porquê disso, eu agradeceria.

Markus Johansson
fonte
5
Você já pensou em remover os arquivos no seu diretório de código e não no próprio diretório de código?
StrongBad
9
Você está enganado que o diretório recém-criado runé igual ao diretório antigo. Ele tem apenas o mesmo nome e diretório pai. Compare isso com você destruindo seu carro antigo e comprando um carro exatamente da mesma cor e modelo: você não gostaria de ficar sentado no carro desfiado e espero que acabe ileso com o novo, não é?
Anthon
2
Anthon: O que suponho é que o caminho é o que identifica o diretório. Para mim, o "cd ../code" é um noop. Estou muito interessado em saber por que não é.
Markus Johansson
2
@MarkusJohansson cd ../codenão é um noop. ..é um atalho para o pai do caminho que você possui ou costumava ter. Se o diretório atual for excluído, o caminho pai ainda poderá existir e, nesse caso, poderá ser alcançado através da avaliação ... Nesse diretório, é feita uma pesquisa por um diretório com o nome 'código'.
Anthon
2
@ MarkusJohansson Em vez de remover e tarar o código, eu recomendo usar qualquer ferramenta de controle de versão disponível. Muito mais fácil compartilhar atualizações (basta pressionar ou puxar) e menos opções para excluir acidentalmente os arquivos errados. E você mantém a versão mais antiga por padrão.
21914 Bernhard

Respostas:

26

Para mim, o "cd ../code" é um noop. Estou muito interessado em saber por que não é.

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

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

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 para que nada seja atribuído a ele pela duração, etc.

Cachinhos Dourados
fonte
3
Esta é a resposta real aqui.
precisa saber é o seguinte
14

Seu shell não faz sempre cdo caminho 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 é verdade 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 cdentrar no diretório atual antes de executar o próximo comando, não conheço nenhum que faça (ou pode ser configurado para fazer isso).

Anthon
fonte
Ilustração folclórica - em teoria, poderia até existir um sistema de arquivos em que o diretório antigo, excluído (ou melhor, desvinculado) ainda exista e seja legível, enquanto o novo também já está em uso. Isso não seria útil na prática com diretórios, mas com arquivos, é bastante comum.
Volker Siegel
4

Na maioria dos sistemas do tipo UNIX, o "diretório atual" de um processo é armazenado no kernel como um descritor de arquivo apontando para esse diretório. O kernel não armazena o caminho do diretório atual: essas informações são rastreadas pelo seu shell.

Um objeto do sistema de arquivos (arquivo ou diretório) só é destruído para sempre quando todos os links do sistema de arquivos desaparecem e não há descritores de arquivo 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, os processos cwdimpedirão 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 próprio diretório continuará a existir como uma espécie de "zumbi". Enquanto isso, você pode criar um novo diretório no mesmo local que o antigo, que é um objeto de 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 novo diretório que reside no endereço antigo.

Por analogia, remover um diretório seria como mover uma casa à força para o depósito de lixo (romper vínculos com o endereço anterior). Se ainda houvesse alguém morando lá (usando-o como seu cwd), eles teriam que sair antes que a casa pudesse ser arrasada. Enquanto isso, uma casa nova em folha pode ser construída no antigo endereço.

nneonneo
fonte
0

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

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

os aliases do bash são mantidos em ~ / .bashrc

MolbOrg
fonte
0

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

cd $ PWD

Para ilustrar, criei um comando fictício deploy:

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

Criou a primeira implementação, cd'd para codificar e depois verificou o conteúdo ls -laipara 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 a 2ª implantação

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 o bash não está usando a entrada de diretório '..' quando você executa, cd ..já que '..' não existe mais - presumo que seja parte de seu tratamento com $ PWD. Alguns outros shell mais antigos / não lidam cd ..com essa situação, você deve primeiro procurar um caminho absoluto.

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

Cd para $PWDe 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 para o diretório atual (.) Mudou?

Se o script de implantação moveu o diretório antigo para outro nome, por exemplo, mv code code.$$no script de implantação acima, ./runfuncionaria, mas até você usá- cd $PWDlo, você estaria 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 o capistrano tem o mesmo problema (eles têm um link simbólico do nome atual para o release atual), portanto, eu uso aliases para fazer o cd nas áreas de produção / preparação, além de definir RAIL_ENV adequadamente:

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'
iheggie
fonte
0

O que eu assumo é que o caminho é o que identifica o diretório.

O caminho para alguma coisa é 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 a pegar e a levar para fora, você não estará mais no seu quarto.

psusi
fonte
0

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

Para ter uma idéia melhor da idéia de que um diretório nos sistemas de arquivos relevantes é mais do que apenas 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

De volta ao original:

$ python
>> importar os
>> os.getcwd ()
'/ home / you / hocus'
>> os.getcwd ()
'/ home / you / pocus'
Evgeni Sergeev
fonte