¿Por qué tengo que salir de un directorio eliminado?

19

En mi servidor tengo una estructura de directorio que se parece a esto:

/myproject/code

Normalmente tengo una conexión ssh con el servidor y 'soporte' en ese directorio:

root@machine:/myproject/code#

Cuando implemento una nueva versión de mi código, el directorio de códigos se elimina, por lo que me queda:

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

Y la única solución que he encontrado es crear un CD y volver a ingresarlo:

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

¿Puedo evitar esto? Es un comportamiento algo extraño. Si tiene una buena explicación de por qué sucede esto, se lo agradecería.

Markus Johansson
fuente
55
¿Has pensado en eliminar los archivos en tu directorio de códigos y no en el directorio de códigos en sí?
StrongBad
99
Se equivoca al decir que el directorio recién creado runes el mismo que el directorio anterior. Solo tiene el mismo nombre y directorio principal. Compare esto con su trituración de su auto viejo y la compra de un auto nuevo del mismo color y modelo: no querría sentarse en el auto destrozado y esperar terminar en el nuevo ileso, ¿verdad?
Anthon
2
Anthon: Lo que supongo es que la ruta es lo que identifica el directorio. Para mí, el "cd ../code" es un noop. Estoy muy interesado en saber por qué no lo es.
Markus Johansson
2
@MarkusJohansson cd ../codeno es un noop. ..es un acceso directo para el padre de la ruta que tiene o solía tener. Si se elimina su directorio actual, la ruta principal aún puede existir, y en este caso se puede llegar evaluando ... En ese directorio se realiza una búsqueda de un directorio con el nombre 'código'.
Anthon
2
@MarkusJohansson En lugar de eliminar y codificar el código, recomendaría utilizar cualquier herramienta de control de versiones disponible. Una actualización mucho más fácil de compartir (solo presionar o tirar) y menos opciones para eliminar accidentalmente los archivos incorrectos. Y mantienes la versión anterior por defecto.
Bernhard

Respuestas:

26

Para mí, el "cd ../code" es un noop. Estoy muy interesado en saber por qué no lo es.

Debido a que los archivos y directorios son fundamentalmente inodos de sistema de archivos , no nombres, este es quizás un detalle de implementación específico para el tipo de sistema de archivos, pero es cierto para todos los sistemas ext, así que me quedaré aquí.

Cuando se crea un nuevo directorio code, se asocia con un nuevo inodo, y ahí es donde está. No hay registros de archivos y directorios eliminados previamente, por lo que no hay ningún medio por el cual el sistema pueda verificar qué inodo solía ocupar y quizás barajar las cosas para que vuelva a ser lo mismo; dicho sistema se volvería rápidamente inviable y, en cualquier caso, probablemente no sea garantía de que volvería a estar allí de nuevo; eso sería algo indeseable, ya que significa que también podría terminar accidentalmente en otro lugar si se crea un directorio que toma su inodo (actualmente no utilizado).

No estoy seguro de si existe esta última posibilidad, o si se realiza un seguimiento del inodo del directorio eliminado actualmente asignado a su directorio de trabajo actual para que no se le asigne nada durante el tiempo, etc.

encerrada dorada
fuente
3
Esta es la verdadera respuesta aquí.
karan.dodia
14

Su shell no siempre hace una cdruta a la que estaba durante el último comando, antes de ejecutar el siguiente comando.

Eliminó el directorio actual y creó un directorio con el mismo nombre, que no es el mismo directorio, solo algo con el mismo nombre / ruta.

Los exploradores de archivos como Nautilus y Windows Explorer normalmente "suben" el árbol de directorios si un directorio se elimina en un sistema de archivos local. Sin embargo, esto no siempre es cierto para los sistemas de archivos en red, en ese caso, a veces, la eliminación no se nota y la reaparición podría hacer que termine en el nuevo directorio.

Un shell podría cdingresar al directorio actual antes de ejecutar el siguiente comando, no conozco ninguno que lo haga (o que pueda configurarse para hacerlo).

Anthon
fuente
Ilustración Fol: en teoría, incluso podría existir un sistema de archivos donde el directorio antiguo, eliminado (o más bien desvinculado) todavía exista y sea legible, mientras que el nuevo ya está en uso. Eso no sería útil en la práctica con directorios, pero con archivos, es bastante común.
Volker Siegel
4

En la mayoría de los sistemas similares a UNIX, el "directorio actual" para un proceso se almacena en el núcleo como un descriptor de archivo que apunta a ese directorio. El núcleo en realidad no almacena la ruta del directorio actual: esa información es rastreada por su shell.

Un objeto del sistema de archivos (archivo o directorio) solo se destruye para siempre cuando todos los enlaces del sistema de archivos desaparecen, y no hay descriptores de archivos que apunten a ese objeto.

Entonces, si un directorio se elimina mientras todavía hay un proceso que lo mantiene como su directorio de trabajo actual, el proceso cwdevitará que el directorio se elimine realmente. Los enlaces del sistema de archivos que anclan el directorio (su entrada en el directorio principal y todos sus contenidos) desaparecerán, pero el directorio en sí mismo seguirá existiendo como una especie de "zombie". Mientras tanto, puede crear un nuevo directorio en la misma ubicación que el anterior, que es un objeto de sistema de archivos completamente diferente pero que comparte la misma ruta.

Por lo tanto, cuando lo hace cd ../code(o, en muchos shells cd .), en realidad está atravesando la jerarquía del sistema de archivos y yendo al nuevo directorio que reside en la dirección anterior.

Por analogía, eliminar un directorio sería como mover a la fuerza una casa al basurero (romper vínculos con la dirección anterior). Si todavía hubiera alguien viviendo allí (usándolo como su cwd), tendrían que irse antes de que la casa pudiera ser arrasada. Mientras tanto, se podría construir una casa nueva en la dirección anterior.

nneonneo
fuente
0

@Anthon aclaró las razones, por qué sucede
Como solución, puede usar un alias , como ejemplo:

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

los alias para bash se guardan en ~ / .bashrc

MolbOrg
fuente
0

Confirmación El directorio de trabajo actual está basado en el número de inodo, no en lo que buscó para llegar allí. Como está usando bash, puede usar $ PWD de la siguiente manera para cd al nuevo directorio del mismo nombre:

cd $ PWD

Para ilustrar, hice un comando de despliegue ficticio:

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

Creé el primer despliegue, lo codifiqué y luego verifiqué el contenido ls -laipara que pueda ver los inodos:

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

Ahora ejecuta el segundo despliegue

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

Y verifique el contenido del directorio ... ¡ahora no hay nada en el directorio! ni siquiera '.' y '..'! A partir de esto, puede ver que bash no está utilizando la entrada de directorio '..' cuando ejecuta cd ..ya que '...' ya no existe; supongo que es parte de su manejo $ PWD. Algunos otros / antiguos shell no se manejan cd ..en esta situación, primero debe cd a una ruta absoluta.

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

Cd $PWDy vuelva a intentarlo:

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

¿Observa cómo cambió el inodo para el directorio actual (.)?

Si la secuencia de comandos de despliegue se trasladó al antiguo directorio a algún otro nombre, por ejemplo, mv code code.$$en el, guión implementar arriba, entonces ./runfuncionaría, pero hasta que utilice cd $PWDque sería correr el viejo código, no el nuevo.

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

La implementación con capistrano tiene el mismo problema (tienen un enlace simbólico desde el nombre actual hasta la versión actual), por lo que uso alias para cd a las áreas de producción / puesta en escena, así como establecer RAIL_ENV adecuadamente:

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
fuente
0

Lo que supongo es que la ruta es lo que identifica el directorio.

El camino hacia algo es cómo se llega allí, no la cosa en sí. El camino a su cama puede ser a través de su habitación, pero una vez que esté en la cama, si alguien lo levanta y lo lleva afuera, ya no estará en su habitación.

psusi
fuente
0

No es una respuesta independiente, pero tengo un punto adicional, que el margen de comentario era demasiado pequeño para contener.

Para tener una mejor idea de la idea de que un directorio en los sistemas de archivos relevantes es más que una ruta, intente mover el directorio de trabajo actual de otro proceso: en un shell, inicie una sesión interactiva de Python:

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

Luego, vaya a otro shell y mueva ese directorio:

$ cd /home/you
$ mv hocus pocus

De vuelta al original:

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