In dem Befehl, den Sie tatsächlich ausgeführt haben, haben Sie nichts verloren! Es gelang, umzubenennen test.txt
in /ben
. Angenommen, test.txt
es 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 directory
ist, was auf der Dose steht: /ben
ist kein Verzeichnis. Sie können weiterhin auf die Datei zugreifen.
Wenn Sie diese Art von Fehler vermeiden und einen Fehler erzwingen möchten, mv
wenn 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 sudo
Bedarf) 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 mv
Befehl versuchen . Es kann jedoch vorkommen, dass Sie mv
mehr 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 mv
in 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 dst
eine Fehlermeldung angezeigt, wenn ich den Namen des Zielverzeichnisses falsch schreibe (z. B. durch Schreiben ), mv: target 'dst' is not a directory
und es gehen keine Daten verloren.
Angenommen, ich würde falsch dst
schreiben, das Trailing weglassen /
und mehrere mv
Befehle ausführen. Das wäre schlecht, denn wenn das Ziel von mv
eine 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 -n
um stillschweigend nicht zu überschreiben. Andernfalls mv
fragen 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.txt
existiert und Sie es nicht überschreiben wollten.
Sie können auch verwenden, -t dest
anstatt dest
am Ende des Befehls zu schreiben , z mv -t dest file*.txt
. Dies verweigert den Betrieb, wenn dest
es 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 dst
anstelle des Verzeichnisses spezifiziere dest
(aber den Schrägstrich behalte!), Würde ich einen mv: failed to access 'dst/': Not a directory
Fehler 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*.txt
in einem gesamten Verzeichnisbaum übereinstimmen ( außer an dest
sich ), 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 , dest
würde dies eine aufgerufene Datei nicht überschreiben, dst
selbst wenn ich dst
stattdessen 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.txt
und 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 dir
besteht 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 -i
Option übergeben, vor jedem Vorgang, der eine Datei überschreiben würde, eine Eingabeaufforderung zu erhalten. Wenn Sie diese nur stillschweigend überspringen möchten, schreiben Sie n
statt i
. Wenn Sie Ihre find
Befehle zuerst testen möchten , können Sie echo
nach, -exec
aber 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 find
es sich um Overkill handelt und der komplizierteste vernünftige Befehl ist mv -it dest/ file*.txt
.)
test.txt
,/ben
ist also in der Tat/ben
kein Verzeichnis (es ist das neuefile.txt
).