Comportamento do bash ao remover o diretório em que você está

6

Estou usando GNU bash, version 4.3.42(1)-release (x86_64-redhat-linux-gnu) .

Eu criei um diretório fictício hello e mudei para lá. Uma vez em /tmp/hello , eu removi o diretório em si.

$ pwd
/tmp/hello
$ rmdir $PWD

Eu verifiquei e ainda estava nesse diretório.

$ pwd
/tmp/hello

Eu então tentei ir para o diretório em si e é claro que não foi possível (mesmo que eu já estivesse lá):

$ cd $PWD
bash: cd: /tmp/hello: No such file or directory

Mas então eu tentei com cd . , como deveria ser o mesmo que cd $PWD . E isso funcionou ... de alguma forma:

$ cd .
cd: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory

Para minha surpresa, agora eu estava em um novo "algo":

$ pwd
/tmp/hello/.

E se eu tentei ir para o diretório anterior, é claro que ele falha:

$ cd -
bash: cd: /tmp/hello: No such file or directory

O engraçado é que nem mesmo uma página man funciona enquanto estiver lá:

$ man cd
man: can't change directory to '': No such file or directory
man: command exited with status 255: (cd  && LESS=-ix8RmPm Manual page cd(1) ?ltline %lt?L/%L.:byte %bB?s/%s..?e (END):?pB %pB\%.. (press h for help or q to quit)$PM Manual page cd(1) ?ltline %lt?L/%L.:byte %bB?s/%s..?e (END):?pB %pB\%.. (press h for help or q to quit)$ MAN_PN=cd(1) less -s)

Por que tudo isso está acontecendo?

    
por fedorqui 23.10.2015 / 12:08

3 respostas

3

Concordando com @BinaryZebra, é justo ressaltar que esta pergunta foi feita antes (por exemplo, Remove um diretório de dentro usando a interface de linha de comando [duplicado] , e pode ser citado ad infinitum ), e os recursos observáveis são bem conhecidos.

O comentário sobre o comportamento relacionado ao POSIX é mais interessante, já que ele pode fornecer algumas informações sobre o comportamento esperado . Os documentos POSIX relevantes são

Na seção Uso do aplicativo do cd, é observado

Since cd affects the current shell execution environment, it is always provided as a shell regular built-in.

Na seção Descrição do cd, o item 10 fornece as informações mais relevantes:

  1. The cd utility shall then perform actions equivalent to the chdir() function called with curpath as the path argument. If these actions fail for any reason, the cd utility shall display an appropriate error message and the remainder of this step shall not be executed. If the -P option is not in effect, the PWD environment variable shall be set to the value that curpath had on entry to step 9 (i.e., before conversion to a relative pathname). If the -P option is in effect, the PWD environment variable shall be set to the string that would be output by pwd -P. If there is insufficient permission on the new directory, or on any parent of that directory, to determine the current working directory, the value of the PWD environment variable is unspecified.

Ou seja, PWD é uma saída do comando cd , em vez de uma entrada e, como tal, é amplamente ignorada pelo comando cd . Tome nota da declaração final sobre "não especificado". POSIX se recusa a dizer o que acontece com $PWD no caso de uma chamada para chdir() falhar.

Na discussão de Variáveis de ambiente para pwd , as notas POSIX referentes a PWD :

An absolute pathname of the current working directory. If an application sets or unsets the value of PWD, the behavior of pwd is unspecified.

Ou seja, POSIX se recusa a especificar qualquer outra forma que $PWD possa ser definida, exceto como um uso bem-sucedido do comando cd (por sua vez, correspondendo uma chamada bem-sucedida a chdir() ).

Em nenhum documento existe texto que possa ser interpretado como dizendo que o caminho é "cacheado", mas apenas que o diretório de trabalho existe (presumivelmente como um valor ) dentro do Ambiente de execução de shell . A discussão do cd em si não menciona a possibilidade de um diretório continuar a existir sem um nome. O documento cd em si também não dá atenção a um diretório não existente. Isso é feito na descrição da função chdir() como uma das várias causas de falha. Por exemplo

[ENOENT]
A component of path does not name an existing directory or path is an empty string.

A descrição de chdir() não menciona nenhum tratamento especial de "." , talvez porque POSIX evita descrever em detalhes o procedimento pelo qual um caminho absoluto é calculado usando getcwd() , por exemplo, permitindo sistemas de arquivos sem "." e ".." . Em caso afirmativo, alguém poderia ter acrescentado um texto para indicar que as implementações podem tratar chdir(".") como não operacional.

Voltando ao passo 10, diz explicitamente:

If these actions fail for any reason, the cd utility shall display an appropriate error message and the remainder of this step shall not be executed.

A atualização de PWD é feita após essa sentença, portanto, não há possibilidade de alterar o valor em caso de falha.

Voltando a pwd , diz da opção -L

If the PWD environment variable contains an absolute pathname of the current directory that does not contain the filenames dot or dot-dot, pwd shall write this pathname to standard output.

e mais tarde

If neither -L nor -P is specified, the pwd utility shall behave as if -L had been specified.

Portanto, há uma cadeia de atos, mas em nenhum lugar uma declaração explícita de que o shell usa a variável PWD como o contêiner do diretório de trabalho. Em vez disso, há os pontos anotados como não especificados que permitem a possibilidade de que algum aplicativo compatível com POSIX possa escolher uma maneira diferente de organizar seus dados, desde que atenda aos pontos de agir como se fossem.

    
por 24.10.2015 / 01:48
2

Repetir uma descrição de alguma interpretação pessoal da documentação do POSIX não ajudará o OP. Existem várias outras questões que explicaram o POSIX em detalhes. E, no entanto, esta questão.

Algumas descrições básicas:
A . É uma característica conhecida do Linux / Unix que um arquivo (diretório) pode ser apagado enquanto está sendo usado. É por isso que você pode continuar vendo um filme depois de apagá-lo. Somente quando o inode da entrada de diretório é removido é que o arquivo realmente desapareceu.

B . Também acontece que o shell mantém um valor interno para o pwd real, mesmo se o valor da variável de ambiente $ PWD for alterado.

O primeiro comentário nesta resposta aceita do @yaegashi mostra onde procurar (a fonte do pwd):

I'm correct. See the source of pwd_builtin(). It just prints the content of the_current_working_directory. – yaegashi Jul 31 at 16:01

Como mostrado, o shell ainda mantém um conhecimento do valor correto de pwd ("/ home / user") mesmo começando com um valor ímpar de PWD.

C . Deve ser fácil entender que o valor mantido pela casca pode ficar fora de sincronia com a realidade em alguns casos.

Fazer um cd . dentro de um diretório apagado parece ser um desses casos. Parece também que o shell adiciona o ponto ao último pwd conhecido na falha.

Suas perguntas:

1 . Remova o dir para o PWD e execute o pwd incorporado.

$ pwd
/tmp/hello
$ rmdir $PWD;   pwd
/tmp/hello

O pwd embutido informa o valor de pwd que o shell retém na memória.
Um /bin/pwd externo informará uma falha.
É interessante relatar que pwd -P (mesmo que um Bash embutido) reportará uma falha:

$ pwd -P
pwd: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory

E, depois de usar o pwd -P embutido, o pwd normal também falha. Eu acredito que é porque o valor do pwd na memória é atualizado.

2. cd $ PWD

I then tried to move to the directory itself and of course it was not possible (even though I was already there):

   $ cd $PWD
   bash: cd: /tmp/hello: No such file or directory

Qualquer tentativa real de seguir o caminho para o diretório falhará no ponto em que um diretório não for lido (como quando não existe).

3. cd.

But then I tried with cd ., as it is supposed to be the same as cd $PWD. And this worked... somehow:

   $ cd .
   cd: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory

O shell tenta acessar o caminho que ele conhece é o pwd e ele falha. E é isso que o shell relata, um fracasso! Não tem problema aqui.

4. Novo caminho.

To my surprise, now I was in a new "something":

$ pwd
/tmp/hello/.

O valor na memória do PWD ficou fora de sincronia com a realidade e um ponto (.) foi adicionado a ele. Como qualquer uso repetido de cd . adicionará um ponto.

$ cd .; pwd
/tmp/hello/./.

E, inesperadamente, um cd .. fará o pwd e $ PWD apenas .. .

$ cd ..; pwd; echo $PWD
..
..
$ cd ..; pwd; echo $PWD
../..
../..

5. PCD anterior.

And if I tried to go to the previous directory, it of course fails:

$ cd -
bash: cd: /tmp/hello: No such file or directory

É assim porque o valor anterior do PWD (armazenado no bash no OLDPWD) não pôde ser seguido.
Foi (como você relatou acima) /tmp/hello/. , que (sendo hello apagado) não pôde ser seguido e faz cd - ou cd $OLDPWD falhar.

$ echo $OLDPWD                 # at this point following your exact procedure.
/tmp/hello/.

6. Páginas de manual

Funny thing also is that not even a man page works while in there:

As páginas do manual funcionaram para mim neste momento, bem, na verdade, em todos os pontos.

    
por 24.10.2015 / 22:06
1

POSIX requer que o caminho do diretório atual seja armazenado em cache e o diretório removido ainda exista sem nome.

cd . aparentemente adicionou essa sequência ao nome atualmente armazenado em cache.

    
por 23.10.2015 / 12:44

Tags