Durch versehentliches Verschieben von Dateien in ein nicht vorhandenes Verzeichnis werden Dateien gelöscht?

8

Ich habe alle Dateien aus einem Verzeichnis mit verschoben mvund versehentlich einen Tippfehler im Zielspeicherort gemacht.

Das System hat die Meldung zurückgegeben, dass das Verzeichnis nicht vorhanden ist, meine Dateien aus dem Quellverzeichnis jedoch gelöscht wurden.

Ist das ein Fehler? Sollte das Verschieben von Dateien an einen nicht vorhandenen Speicherort die zu verschiebenden Dateien löschen? (Dies ist unter Ubuntu 18.04.2 LTS.)


Die Besonderheiten waren:

  1. Erstellte test.txtDatei.
  2. Verschob die Datei nach /benmit sudo.
  3. Die Datei ist verschwunden. /benist nicht vorhanden.

Die Befehle und Ausgaben waren:

ben.b@c-w46:~/Desktop/test-folder$ sudo mv test.txt /ben
ben.b@c-w46:~/Desktop/test-folder$ cd /ben
bash: cd: /ben: Not a directory
ben berizovsky
quelle
In Ihrem Fall haben Sie umbenannt test.txt, /benist also in der Tat /benkein Verzeichnis (es ist das neue file.txt).
fkraiem
Warum sollte es umbenennen, wenn ich mv verwenden würde?
Ben Berizovsky
Denn so mvfunktioniert es.
Fkraiem
Wie kann ich diese test.txt finden? oder 'es ist für immer weg?
Ben Berizovsky
@benberizovsky Greifen Sie einfach auf die Datei in /, as zu /ben. Sie können es beispielsweise zurückschieben. Ich habe eine Antwort zu diesem und dem allgemeineren Thema gepostet.
Eliah Kagan

Antworten:

14

In dem Befehl, den Sie tatsächlich ausgeführt haben, haben Sie nichts verloren! Es gelang, umzubenennen test.txtin /ben. Angenommen, test.txtes handelt sich um eine reguläre Datei, ebenso wie die neue /ben(schließlich handelt es sich um dieselbe Datei).

Der Grund, den Sie sehen, bash: cd: /ben: Not a directoryist, was auf der Dose steht: /benist kein Verzeichnis. Sie können weiterhin auf die Datei zugreifen.

Wenn Sie diese Art von Fehler vermeiden und einen Fehler erzwingen möchten, mvwenn das Ziel kein Verzeichnis ist, schreiben Sie ein Trailing /darauf oder verwenden Sie -t dir. Zum Beispiel hätte eines dieser Probleme das (sehr geringfügige!) Problem verhindert, das Sie (bei sudoBedarf) hatten:

mv test.txt /ben/  # no action, unless `/ben` is an existing directory
mv -t /ben test.txt  # same deal, -t doesn't accept regular-file operands
mv -t /ben/ test.txt  # you can even do both if you want

Informationen über die in Ihrer Frage beschriebene allgemeine Situation - über den Verlust von Dateien durch den Versuch, sie zu verschieben - und darüber, was schief gehen kann und was nicht, folgen.


Wie Rinzwind sagt , sollte das Verschieben von Dateien in ein nicht vorhandenes Zielverzeichnis keinen Datenverlust verursachen, wenn Sie es mit einem einzigen mvBefehl versuchen . Es kann jedoch vorkommen, dass Sie mvmehr als einmal ausgeführt haben, z. B. in einer Shell-Schleife.

Angenommen, ich habe:

ek@Apok:~/tmp$ ls -F
dest/       file02.txt  file04.txt  file06.txt  file08.txt  file10.txt
file01.txt  file03.txt  file05.txt  file07.txt  file09.txt

Um all diese Dateien zu verschieben dest, sollte ich alle ihre Namen mvin einem Befehl wie mv file*.txt dest/oder übergeben mv file*.txt dest. In beiden Fällen - das heißt, ob ich den Namen des Zielverzeichnisses mit einem abschließenden Schrägstrich schreibe oder nicht - ist dies das Richtige. In beiden Fällen wird dsteine Fehlermeldung angezeigt, wenn ich den Namen des Zielverzeichnisses falsch schreibe (z. B. durch Schreiben ), mv: target 'dst' is not a directoryund es gehen keine Daten verloren.

Angenommen, ich würde falsch dstschreiben, das Trailing weglassen /und mehrere mvBefehle ausführen. Das wäre schlecht, denn wenn das Ziel von mveine reguläre Datei ist, mv ersetzt es diese!

ek@Apok:~/tmp$ mv file01.txt dst  # bad if dst exists but isn't a directory
ek@Apok:~/tmp$ mv file02.txt dst  # bad, I just lost the old file01.txt!

Aus diesem Grund bevorzugen viele Leute immer schreiben Zielverzeichnisse mit einem nachgestellten /in mv:

ek@Apok:~/tmp$ mv file03.txt dst/
mv: failed to access 'dst/': Not a directory

Sie können verwenden mv -i, um Sie vor dem Überschreiben zu fragen oder mv -num stillschweigend nicht zu überschreiben. Andernfalls mvfragen Sie vor dem Überschreiben nur, ob das Ziel eine schreibgeschützte Datei ist. Ein Grund, dies in Betracht zu ziehen, besteht darin, dass es andere Fälle abdeckt, z. B. mv file01.txt dest/wenn Sie nicht bemerkt haben, dass es dest/file01.txtexistiert und Sie es nicht überschreiben wollten.

Sie können auch verwenden, -t destanstatt destam Ende des Befehls zu schreiben , z mv -t dest file*.txt. Dies verweigert den Betrieb, wenn destes sich um eine reguläre Datei handelt, unabhängig davon, ob Sie ein Trailing schreiben oder nicht /.


Die Verwendung eines automatisierten Mechanismus zum Ausführen mehrerer solcher Befehle kann das Problem erheblich verschärfen. Zum Beispiel ist der Befehl , wie geschrieben,for f in file*.txt; do mv "$f" dest/; done unnötig kompliziert, aber sicher, denn wenn ich versehentlich die Datei dstanstelle des Verzeichnisses spezifiziere dest(aber den Schrägstrich behalte!), Würde ich einen mv: failed to access 'dst/': Not a directoryFehler pro Datei erhalten. Wenn ich jedoch den nachgestellten weggelassen /, dann wäre es jede Datei umbenennen dst, ersetzt die vorherige dst, und nur die letzte Datei bleiben würde.

Ähnliche schlechte Ergebnisse können erzielt werden find, auch in Situationen, in denen die Verwendung sinnvoll sein kann find(jedoch anders und dennoch mit besonderer Sorgfalt). Angenommen, ich wollte alle Dateien, die mit dem Glob file*.txtin einem gesamten Verzeichnisbaum übereinstimmen ( außer an destsich ), in das Verzeichnis verschieben dest. Ich könnte zuerst darüber nachdenken, dies zu verwenden:

find . -path ./dest -prune -o -name 'file*.txt' -exec mv {} dest/ \;  # bad, don't use

Da ich ein abschließendes /Schreiben dest/anstelle von eingefügt habe , destwürde dies eine aufgerufene Datei nicht überschreiben, dstselbst wenn ich dststattdessen schreiben würde dest. Es besteht jedoch das Problem, dass bereits kopierte Dateien überschrieben werden, wenn Dateien in verschiedenen Teilen des Verzeichnisbaums denselben Namen haben. Wenn es zum Beispiel ein a/file01.txtund ein gibt b/file01.txt, überschreibt eines das andere. Um dies ebenfalls zu vermeiden, ist es besser, so etwas zu verwenden:

find -path ./dest -prune -o -name 'file*.txt' -exec mv -it dest/ {} \;  # okay

Der andere Vorteil -t dirbesteht darin, dass Sie das Zielverzeichnis angeben können, bevor die Elemente verschoben werden. Es ist daher mit der +Form kompatibel -exec, bei der mehrere Elemente an einen Befehl übergeben werden, wodurch weniger Befehle ausgeführt werden (häufig nur einer):

find -path ./dest -prune -o -name 'file*.txt' -exec mv -it dest/ {} +  # good

In beiden Fällen (sie sind bis auf \;vs. gleich +) habe ich auch die -iOption übergeben, vor jedem Vorgang, der eine Datei überschreiben würde, eine Eingabeaufforderung zu erhalten. Wenn Sie diese nur stillschweigend überspringen möchten, schreiben Sie nstatt i. Wenn Sie Ihre findBefehle zuerst testen möchten , können Sie echonach, -execaber vor dem Rest des Befehls schreiben , um zu drucken, was ausgeführt werden soll. Zum Beispiel:

ek@Apok:~/tmp$ find -path ./dest -prune -o -name 'file*.txt' -exec echo mv -it dest/ {} +
mv -it dest/ ./file02.txt ./file06.txt ./file10.txt ./file09.txt ./file01.txt ./file04.txt ./file05.txt ./file07.txt ./file03.txt ./file08.txt

(Natürlich befindet sich das in dem Originalverzeichnis, das ich gezeigt habe, wo sich alle zu verschiebenden Dateien am selben Speicherort befinden und wo findes sich um Overkill handelt und der komplizierteste vernünftige Befehl ist mv -it dest/ file*.txt.)

Eliah Kagan
quelle
Beide Antworten haben mir geholfen, aber ich musste mich dafür entscheiden. Vielen Dank, ich danke Ihnen beiden.
Ben Berizovsky
@benberizovsky Ein einfacherer Ansatz könnte darin bestehen, sich für die automatische Vervollständigung auf die Taste <kbd> Tab </ kbd> zu verlassen. Wenn durch Drücken das Zielverzeichnis für Sie nicht automatisch vervollständigt werden kann, ist das Verzeichnis im Zielpfad nicht vorhanden. An diesem Punkt sollten Sie nach Tippfehlern und anderen Details suchen.
code_dredd
8

Nein, was Sie vorschlagen, sollte (!) Nicht möglich sein. Sie müssen wahrscheinlich am Ziel besser aussehen. Verwenden Sie historydiese Option , um eine Liste der zuvor ausgegebenen Befehle abzurufen.

Einige Sachen:

  • Solange sich der Zielspeicherort auf derselben Partition wie die Quelle befindet, werden keine Daten verschoben. Nur der Name im Verzeichniseintrag wird geändert.

Wenn ein Schritt getan wird ...

  • Informationen zur Funktionsweise von mv und insbesondere zu diesem Teil finden Sie unter info coreutils 'mv invocation'(Online-Version https://www.gnu.org/software/coreutils/manual/html_node/mv-invocation.html#mv-invocation ).

    Zuerst wird derselbe Code verwendet, der von 'cp ​​-a' zum Kopieren der angeforderten Verzeichnisse und Dateien verwendet wird, und dann (vorausgesetzt, die Kopie war erfolgreich) werden die Originale entfernt. Wenn die Kopie fehlschlägt, wird der Teil, der auf die Zielpartition kopiert wurde, entfernt. Wenn Sie drei Verzeichnisse von einer Partition auf eine andere kopieren würden und die Kopie des ersten Verzeichnisses erfolgreich wäre, das zweite jedoch nicht, würde das erste auf der Zielpartition und das zweite und dritte auf der ursprünglichen Partition verbleiben.

  • Ein Zug besteht also aus 2 Teilen:

    1. ein cp -a
    2. ein mv

    Der Entfernungsteil des Verschiebens ist abgeschlossen, nachdem bestätigt wurde, dass die Kopie korrekt ausgeführt wurde.

  • Wenn Ihre MV aus mehreren Dateien besteht, erfolgt das Kopieren und Verschieben dazwischen. Also a

    mv a b c d e f /dir/
    

    werde ein tun

    cp a /dir/
    rm a
    ...
    cp f /dir/
    rm f
    

    Wenn es also ein Problem zwischen a und f gibt, ist die Bewegung von a und bis zu dem Punkt, an dem das Problem aufgetreten ist, beendet. Dies gilt auch für die Verwendung von Platzhaltern.


In Bezug auf die Bearbeitung

sudo mv test.txt /ben

Dadurch wird test.txt nach / verschoben und in ben umbenannt. Und

ben.b@c-w46:~/Desktop/test-folder$ cd /ben
bash: cd: /ben: Not a directory

richtig fehler raus. Mach a

ls -l /ben

und es wird die Datei anzeigen.

Was Sie immer tun sollten, ist ein / anzuhängen, wenn Sie eine Datei in ein Verzeichnis verschieben möchten.

sudo mv test.txt /ben/

würde ausfallen, da / ben / nicht existiert.

Rinzwind
quelle
bearbeitet meine Frage
Ben Berizovsky
aktualisiert, um Ihr Beispiel widerzuspiegeln.
Rinzwind