Pourquoi dois-je sortir un CD d'un répertoire supprimé?


19

Sur mon serveur, j'ai une structure de répertoires ressemblant à ceci:

/myproject/code

J'ai normalement une connexion ssh au serveur et 'stand' dans ce répertoire:

root@machine:/myproject/code#

Lorsque je déploie une nouvelle version de mon code, le répertoire de code est supprimé, il me reste donc:

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

Et la seule solution que j'ai trouvée est de sortir et de rentrer en cd:

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

Puis-je éviter cela? C'est un comportement quelque peu étrange. Si vous avez une belle explication pourquoi cela se produit, je l'apprécierais.


5
Avez-vous pensé à supprimer les fichiers de votre répertoire de code et non le répertoire de code lui-même?
StrongBad

9
Vous vous trompez que le répertoire nouvellement créé runest le même que l'ancien répertoire. Il n'a que le même nom et le même répertoire parent. Comparez cela à la destruction de votre ancienne voiture et à l'achat d'une nouvelle voiture de la même couleur et du même modèle: vous ne voudriez pas vous asseoir dans la voiture déchiquetée et espérer que vous vous retrouviez indemne avec la nouvelle, n'est-ce pas?
Anthon

2
Anthon: Ce que je suppose, c'est que le chemin est ce qui identifie le répertoire. Pour moi, le "cd ../code" est un noop. Je suis très intéressé à savoir pourquoi ce n'est pas le cas.
Markus Johansson

2
@MarkusJohansson cd ../coden'est pas un noop. ..est un raccourci pour le parent du chemin que vous avez ou avez utilisé. Si votre répertoire actuel est supprimé, le chemin parent peut toujours exister et, dans ce cas, être accessible en évaluant ... Dans ce répertoire, une recherche est effectuée pour un répertoire avec le nom «code».
Anthon

2
@MarkusJohansson Au lieu de supprimer et de tarifier le code, je recommande fortement d'utiliser n'importe quel outil de contrôle de version disponible. Mise à jour beaucoup plus facile à partager (il suffit de pousser ou de tirer) et moins d'options pour supprimer accidentellement les mauvais fichiers. Et vous conservez l'ancienne version par défaut.
Bernhard

Réponses:


26

Pour moi, le "cd ../code" est un noop. Je suis très intéressé à savoir pourquoi ce n'est pas le cas.

Parce que les fichiers et les répertoires sont fondamentalement des inodes de système de fichiers , pas des noms - c'est peut-être un détail d'implémentation spécifique au type de système de fichiers, mais c'est vrai pour tous les systèmes ext, donc je m'en tiendrai ici.

Lorsqu'un nouveau répertoire codeest créé, il est associé à un nouvel inode, et c'est là qu'il se trouve. Il n'y a aucun enregistrement des fichiers et répertoires précédemment supprimés, il n'y a donc aucun moyen par lequel le système pourrait vérifier quel inode il occupait et peut-être mélanger les choses pour qu'il en soit de même; un tel système deviendrait rapidement irréalisable, et en tout cas, il n'y a probablement aucune garantie que vous y retourniez - ce serait en quelque sorte indésirable, car cela signifie que vous pourriez également accidentellement vous retrouver ailleurs si un répertoire est créé qui prend votre inode (actuellement inutilisé).

Je ne sais pas si cette dernière possibilité existe, ou si l'inode du répertoire supprimé actuellement affecté à votre répertoire de travail actuel est suivi afin que rien ne lui soit affecté pendant la durée, etc.


3
C'est la vraie réponse ici.
karan.dodia

14

Votre shell ne fait pas à chaque fois un cdchemin vers le chemin où il se trouvait lors de la dernière commande, avant d'exécuter la commande suivante.

Vous avez supprimé le répertoire actuel et créé un répertoire avec le même nom, qui n'est pas le même répertoire, juste quelque chose avec le même nom / chemin.

Les navigateurs de fichiers comme Nautilus et l'Explorateur Windows "remontent" normalement l'arborescence des répertoires si un répertoire est supprimé sur un système de fichiers local. Cependant, ce n'est pas toujours le cas pour les systèmes de fichiers en réseau, dans ce cas, parfois, la suppression n'est pas remarquée et la réapparition pourrait vous faire vous retrouver dans le nouveau répertoire.

Un shell pourrait cdpénétrer dans le répertoire courant avant d'exécuter la commande suivante, je n'en connais aucun qui le fasse (ou peut être configuré pour le faire).


Fol illustration - en théorie, il pourrait même exister un système de fichiers où l'ancien répertoire supprimé (ou plutôt non lié) existe toujours et est lisible, tandis que le nouveau est déjà utilisé. Cela ne serait pas utile dans la pratique avec les répertoires, mais avec les fichiers, c'est assez courant.
Volker Siegel

4

Sur la plupart des systèmes de type UNIX, le "répertoire courant" d'un processus est stocké dans le noyau en tant que descripteur de fichier pointant vers ce répertoire. Le noyau ne stocke pas réellement le chemin du répertoire courant: ces informations sont suivies par votre shell.

Un objet de système de fichiers (fichier ou répertoire) n'est détruit pour de bon que lorsque tous les liens du système de fichiers vers celui-ci ont disparu et qu'aucun descripteur de fichier ne pointe vers cet objet.

Donc, si un répertoire est supprimé alors qu'il y a encore un processus le tenant comme son répertoire de travail actuel, le processus cwdempêchera le répertoire d'être vraiment supprimé. Les liens du système de fichiers qui ancrent le répertoire (son entrée dans le répertoire parent et tout son contenu) auront disparu, mais le répertoire lui-même continuera d'exister comme une sorte de "zombie". Pendant ce temps, vous pouvez créer un tout nouveau répertoire au même emplacement que l'ancien, qui est un objet de système de fichiers complètement différent mais qui partage le même chemin.

Ainsi, lorsque vous le faites cd ../code(ou, sur de nombreux shells, cd .), vous parcourez en fait la hiérarchie du système de fichiers et accédez au nouveau répertoire qui réside à l'ancienne adresse.

Par analogie, la suppression d'un répertoire reviendrait à déplacer de force une maison vers le dépotoir (rompre les liens avec l'adresse précédente). S'il y avait toujours quelqu'un là-bas (l'utilisant comme leur cwd), ils devraient partir avant que la maison ne soit rasée. En attendant, une maison neuve pourrait être construite à l'ancienne adresse.


0

@Anthon a expliqué les raisons pour lesquelles cela se produit.
Comme solution, vous pouvez utiliser un alias , par exemple:

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

les alias pour bash sont conservés dans ~ / .bashrc


0

Confirmation Le répertoire de travail actuel EST basé sur le numéro d'inode, pas sur ce que vous avez recherché pour y arriver. Puisque vous utilisez bash, vous pouvez utiliser $ PWD comme suit pour accéder au nouveau répertoire du même nom:

cd $ PWD

Pour illustrer, j'ai fait une commande de déploiement factice:

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

Créé le premier déploiement, cd'd pour coder puis vérifié le contenu avec ls -laiafin que vous puissiez voir les 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

Exécutez maintenant le 2e déploiement

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

Et vérifiez le contenu du répertoire ... maintenant il n'y a rien dans le répertoire! pas même '.' et '..'! De cela, vous pouvez voir que bash n'utilise pas l'entrée de répertoire «..» lorsque vous exécutez cd ..depuis que «..» n'existe plus - je suppose que sa partie de sa gestion de $ PWD. Certains autres / anciens shell ne gèrent pas cd ..dans cette situation, vous devez d'abord accéder à un chemin absolu.

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

Cd $PWDet réessayez:

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

Notez comment l'inode du répertoire actuel (.) A changé?

Si votre script de déploiement a déplacé l'ancien répertoire vers un autre nom, par exemple mv code code.$$dans le script de déploiement ci-dessus, ./runcela fonctionnerait, mais jusqu'à ce que vous l'utilisiez, cd $PWDvous exécutez l' ancien code, pas le nouveau.

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

Le déploiement à l'aide de capistrano a le même problème (ils ont un lien symbolique du nom actuel vers la version actuelle), donc j'utilise des alias pour cd vers les zones de production / mise en scène ainsi que pour définir RAIL_ENV de manière appropriée:

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'

0

Ce que je suppose, c'est que le chemin est ce qui identifie le répertoire.

Le chemin vers quelque chose est la façon dont vous y arrivez, pas la chose elle-même. Le chemin menant à votre lit peut être à travers votre chambre, mais une fois que vous êtes au lit, si quelqu'un le ramasse et le porte à l'extérieur, vous n'êtes plus dans votre chambre.


0

Pas une réponse autonome, mais j'ai un point supplémentaire, que la marge de commentaires était trop petite pour contenir.

Pour avoir une meilleure idée de l'idée qu'un répertoire dans les systèmes de fichiers appropriés est plus qu'un simple chemin, essayez de déplacer le répertoire de travail actuel d'un autre processus: dans un shell, démarrez une session Python interactive:

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

Ensuite, allez dans un autre shell et déplacez ce répertoire:

$ cd /home/you
$ mv hocus pocus

Retour à l'original:

$ python
>> importer os
>> os.getcwd ()
'/ home / vous / hocus'
>> os.getcwd ()
'/ home / vous / pocus'
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.