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.)
test.txt,/benist also in der Tat/benkein Verzeichnis (es ist das neuefile.txt).