Warum muss ich aus einem gelöschten Verzeichnis aussteigen?


19

Auf meinem Server habe ich eine Verzeichnisstruktur, die ungefähr so ​​aussieht:

/myproject/code

Normalerweise habe ich eine SSH-Verbindung zum Server und 'stehe' in diesem Verzeichnis:

root@machine:/myproject/code#

Wenn ich eine neue Version meines Codes bereitstelle, wird das Codeverzeichnis entfernt.

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

Und die einzige Lösung, die ich gefunden habe, ist das Aus- und Einspielen von CDs:

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

Kann ich das vermeiden? Es ist ein etwas merkwürdiges Verhalten. Wenn Sie eine nette Erklärung haben, warum dies passiert, würde ich es begrüßen.


5
Haben Sie darüber nachgedacht, die Dateien in Ihrem Codeverzeichnis und nicht im Codeverzeichnis selbst zu entfernen?
StrongBad

9
Sie irren sich, dass das neu erstellte Verzeichnis runmit dem alten Verzeichnis identisch ist. Es hat nur denselben Namen und dasselbe übergeordnete Verzeichnis. Vergleichen Sie dies damit, dass Sie Ihr altes Auto zerkleinern und ein neues Auto mit genau der gleichen Farbe und dem gleichen Modell kaufen: Sie möchten nicht im zerkleinerten Auto sitzen und hoffen, dass Sie unversehrt auf dem neuen landen, oder?
Anthon

2
Anthon: Ich gehe davon aus, dass der Pfad das Verzeichnis identifiziert. Für mich ist der "cd ../code" ein Noop. Ich bin sehr daran interessiert zu hören, warum es nicht so ist.
Markus Johansson

2
@ MarkusJohansson cd ../codeist kein Noop. ..ist eine Verknüpfung für das übergeordnete Element des Pfads, den Sie haben oder früher hatten. Wenn Ihr aktuelles Verzeichnis gelöscht wird, ist der übergeordnete Pfad möglicherweise noch vorhanden und in diesem Fall durch Auswerten erreichbar ... In diesem Verzeichnis wird nach einem Verzeichnis mit dem Namen 'code' gesucht.
Anthon

2
@MarkusJohansson Anstatt Code zu entfernen und zu tarrieren, würde ich dringend empfehlen, ein verfügbares Tool zur Versionskontrolle zu verwenden. Weitaus einfacher zu teilendes Update (einfach drücken oder ziehen) und weniger Optionen, um versehentlich die falschen Dateien zu löschen. Und Sie behalten standardmäßig eine ältere Version.
Bernhard

Antworten:


26

Für mich ist der "cd ../code" ein Noop. Ich bin sehr daran interessiert zu hören, warum es nicht so ist.

Da Dateien und Verzeichnisse im Grunde genommen Inodes von Dateisystemen sind , keine Namen - dies ist möglicherweise ein Implementierungsdetail, das für den Dateisystemtyp spezifisch ist, aber es gilt für alle ext-Systeme, also werde ich mich hier daran halten.

Wenn ein neues Verzeichnis codeerstellt wird, ist es mit einem neuen Inode verknüpft, und dort befindet es sich. Es gibt keine Aufzeichnungen über zuvor gelöschte Dateien und Verzeichnisse, so dass das System nicht überprüfen kann, welchen Inode es verwendet hat, um Dinge zu belegen und möglicherweise zu mischen, damit es wieder dasselbe ist. Ein solches System würde schnell unbrauchbar werden und in jedem Fall ist es wahrscheinlich keine Garantie, dass Sie wieder da sind - das wäre unerwünscht, da Sie auch versehentlich woanders landen könnten, wenn ein Verzeichnis erstellt wird das nimmt Ihre (derzeit unbenutzte) Inode.

Ich bin nicht sicher, ob diese letzte Möglichkeit besteht oder ob der Inode des gelöschten Verzeichnisses, das Ihrem aktuellen Arbeitsverzeichnis zugewiesen ist, verfolgt wird, sodass ihm für die Dauer usw. nichts zugewiesen wird.


3
Dies ist die wahre Antwort hier.
karan.dodia

14

Ihre Shell führt nicht jedes Mal einen cdBefehl an dem Pfad aus, in dem sie sich während des letzten Befehls befunden hat, bevor der nächste Befehl ausgeführt wird.

Sie haben das aktuelle Verzeichnis gelöscht und ein Verzeichnis mit demselben Namen erstellt, bei dem es sich nicht um dasselbe Verzeichnis handelt, sondern nur um etwas mit demselben Namen / Pfad.

Dateibrowser wie Nautilus und Windows Explorer "gehen" normalerweise in der Verzeichnisstruktur nach oben, wenn ein Verzeichnis in einem lokalen Dateisystem gelöscht wird. Dies gilt jedoch nicht immer für vernetzte Dateisysteme. In diesem Fall wird das Löschen manchmal nicht bemerkt und das erneute Auftreten kann dazu führen, dass Sie in das neue Verzeichnis gelangen.

Eine Shell könnte cdvor dem Ausführen des nächsten Befehls in das aktuelle Verzeichnis gelangen, mir sind keine bekannt, die dies tun (oder dafür konfiguriert werden können).


Zur Veranschaulichung: Theoretisch könnte es sogar ein Dateisystem geben, in dem das alte, gelöschte (oder eher nicht verknüpfte) Verzeichnis noch vorhanden und lesbar ist, während das neue ebenfalls bereits verwendet wird. Das wäre in der Praxis mit Verzeichnissen nicht sinnvoll, aber mit Dateien ist es ziemlich verbreitet.
Volker Siegel

4

Auf den meisten UNIX-ähnlichen Systemen wird das "aktuelle Verzeichnis" für einen Prozess im Kernel als Dateideskriptor gespeichert, der auf dieses Verzeichnis verweist. Der Kernel speichert nicht den Pfad des aktuellen Verzeichnisses: Diese Informationen werden von Ihrer Shell verfolgt.

Ein Dateisystemobjekt (Datei oder Verzeichnis) wird nur dann endgültig zerstört, wenn alle Dateisystemverknüpfungen zu diesem Objekt verschwunden sind und keine Dateideskriptoren auf dieses Objekt verweisen.

Wenn also ein Verzeichnis entfernt wird, während es noch einen Prozess gibt, der es als aktuelles Arbeitsverzeichnis enthält, verhindert der Prozess, cwddass das Verzeichnis wirklich gelöscht wird. Die Dateisystemverknüpfungen, die das Verzeichnis verankern (sein Eintrag im übergeordneten Verzeichnis und sein gesamter Inhalt), gehen verloren, aber das Verzeichnis selbst wird weiterhin als eine Art "Zombie" existieren. In der Zwischenzeit können Sie ein brandneues Verzeichnis am selben Speicherort wie das alte erstellen, bei dem es sich um ein völlig anderes Dateisystemobjekt handelt, das jedoch denselben Pfad aufweist.

Wenn Sie dies tun cd ../code(oder auf vielen Shells cd .), durchlaufen Sie tatsächlich die Dateisystemhierarchie und wechseln in das neue Verzeichnis, das sich an der alten Adresse befindet.

In analoger Weise würde das Entfernen eines Verzeichnisses bedeuten, dass ein Haus gewaltsam auf die Müllkippe verschoben wird (wodurch die Bindung zur vorherigen Adresse unterbrochen wird). Wenn dort noch jemand lebte (der es als sein Eigentum benutzt cwd), musste er gehen, bevor das Haus zerstört werden konnte. In der Zwischenzeit könnte ein brandneues Haus an der alten Adresse gebaut werden.


0

@Anthon hat Gründe geklärt, warum es passiert
Als Lösung können Sie einen Alias ​​verwenden , zum Beispiel:

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

Aliase für bash werden in ~ / .bashrc gespeichert


0

Bestätigen Das aktuelle Arbeitsverzeichnis basiert auf der Inode-Nummer und nicht auf dem, wonach Sie gesucht haben, um dorthin zu gelangen. Da Sie bash verwenden, können Sie $ PWD wie folgt verwenden, um in das neue Verzeichnis mit dem gleichen Namen zu wechseln:

cd $ PWD

Zur Veranschaulichung habe ich einen Dummy-Bereitstellungsbefehl erstellt:

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

Hat die erste Bereitstellung erstellt, eine CD zum Codieren erstellt und dann den Inhalt mit überprüft, ls -laidamit Sie die Inodes sehen können:

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

Führen Sie nun die zweite Bereitstellung aus

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

Und überprüfe den Inhalt des Verzeichnisses ... jetzt ist nichts mehr im Verzeichnis! nicht mal '.' und '..'! Daran können Sie erkennen, dass die Bash den Verzeichniseintrag cd ..'..' nicht verwendet, wenn Sie sie ausführen, da '..' nicht mehr vorhanden ist - ich nehme an, dass dies Teil der $ PWD-Behandlung ist. Einige andere / ältere Shells funktionieren nichtcd .. in dieser Situation , Sie müssen zuerst einen absoluten Pfad angeben.

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

CD an $PWDund versuchen Sie es erneut:

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

Beachten Sie, wie sich der Inode für das aktuelle Verzeichnis (.) Geändert hat.

Wenn Ihr Bereitstellungsskript das alte Verzeichnis in einen anderen Namen verschieben würde, z. B. mv code code.$$im obigen Bereitstellungsskript, ./runwürde dies funktionieren, aber bis Sie es verwenden cd $PWD, würden Sie den alten Code ausführen, nicht den neuen.

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

Die Bereitstellung mit capistrano hat das gleiche Problem (sie haben einen Symlink vom aktuellen Namen zur aktuellen Version), daher verwende ich Aliase, um zu den Produktions- / Staging-Bereichen zu wechseln und RAIL_ENV entsprechend einzustellen:

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

Ich gehe davon aus, dass der Pfad das Verzeichnis identifiziert.

Der Weg zu etwas ist, wie man dorthin kommt, nicht das Ding selbst. Der Weg zu Ihrem Bett führt vielleicht durch Ihr Zimmer, aber wenn Sie im Bett sind und jemand es aufhebt und es nach draußen trägt, sind Sie nicht mehr in Ihrem Zimmer.


0

Keine in sich geschlossene Antwort, aber ich habe einen zusätzlichen Punkt, für den der Kommentarbereich zu klein war.

Um ein besseres Gefühl dafür zu bekommen, dass ein Verzeichnis in den relevanten Dateisystemen mehr als nur ein Pfad ist, verschieben Sie das aktuelle Arbeitsverzeichnis eines anderen Prozesses: Starten Sie in einer Shell eine interaktive Python-Sitzung:

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

Wechseln Sie dann zu einer anderen Shell und verschieben Sie das Verzeichnis:

$ cd /home/you
$ mv hocus pocus

Zurück zum Original:

$ python
>> import os
>> os.getcwd ()
'/ home / du / hokus'
>> os.getcwd ()
'/ home / du / pocus'
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.