Warum kann mv nicht mit der Existenz eines gleichnamigen Verzeichnisses im Ziel umgehen?

8

mv Ein Verzeichnis kann nicht an ein Ziel mit einem gleichnamigen Verzeichnis verschoben werden:

$ mv fortran/ imperative_PLs/
mv: cannot move ‘fortran/’ to ‘imperative_PLs/fortran’: Directory not empty
  1. Warum funktioniert das mvin diesem Fall nicht? Kann das aus den Systemaufrufen erklärt werden mv? (Vergleiche mit rsyncwelcher Dose)

  2. Warum mvfunktioniert es in diesem Fall nicht? Was ist die Begründung oder der Punkt?

Tim
quelle

Antworten:

6
  1. mvfunktioniert in diesem Fall nicht, da es nicht dafür ausgelegt ist. Die Systemaufrufe sind (wahrscheinlich) entweder

    • Wechseln Sie in dasselbe Dateisystem: rename(ursprünglich linkund unlink)
    • Über Dateisysteme wechseln: rekursive Dateikopie gefolgt von rekursiv unlink
  2. Meinung: Ich denke, es ist nicht so sehr so, dass es nicht funktioniert, da es nicht für diesen Anwendungsfall entwickelt wurde. Für ein "einfaches" Tool, das eine Sache gut machen soll, müssten Sie eine Reihe von Schaltern bereitstellen, um anzugeben, zu mvwelchem ​​dieser Aktionspfade Sie gehen sollen:

    • Mit einem Fehler zu retten, wie in der aktuellen Implementierung
    • Zum Zusammenführen wird ein Fehler gemeldet, wenn bereits eine Datei vorhanden ist
    • Ersetzen Sie zum Zusammenführen alle bereits vorhandenen Zieldateien

Wenn die Zusammenführung / ersetzen Aktion ist das, was Sie wollen, können Sie es implementieren leicht genug , um mit cpgefolgt von rmoder durch einen der Dateibaum kopieren Dienstprogramme tar, paxusw.

Roaima
quelle
Vielen Dank. (1) Enthält rmAnruf rmdir()neben rename()? (2) "In dasselbe Dateisystem verschieben: Umbenennen (ursprünglich verknüpfen und Verknüpfung aufheben)", was meinen Sie mit "ursprünglich verknüpfen und Verknüpfung aufheben"? (3) Warum beim Verschieben zwischen Dateisystemen "rekursive Dateikopie gefolgt von rekursiver Verknüpfung"?
Tim
mein Tippfehler. Ich meinte mvstatt rm.
Tim
@ Tim: Im gleichen Dateisystem, mvverwendet nur rename() . Funktioniert zwischen Dateisystemen mvim Wesentlichen genauso wie cp -r(aber Vorsicht vor dem Umgang mit speziellen Dateien wie Symlinks, Geräten usw., die traditionell nicht gut verarbeitet werden cp -r), gefolgt von rm -r, also wird sie rmdir()in diesem Modus verwendet.
Guntram Blohm unterstützt Monica
10

mvund rsyncsind keine ähnlichen Programme. Insbesondere mvwird häufig versucht, Objekte einfach umzubenennen. Wenn es sich im selben Dateisystem befindet, wird der Inhalt überhaupt nicht kopiert.

Wenn Sie dies noch nicht getan haben imperative_PLs/fortran, mvnehmen Sie das vorhandene fortranVerzeichnis und benennen Sie es an dieser Stelle im Baum um.

Sie haben jedoch bereits ein Verzeichnis (mit Inhalten) an diesem Speicherort. Da ein Name nur auf ein einzelnes Objekt verweisen kann, müsste das vorhandene Verzeichnis entweder entfernt oder umbenannt werden. mvgeht davon aus, dass Sie dies auch nicht möchten und bricht ab.

rsyncKopiert stattdessen die einzelnen Dateien und anderen Inhalte fortranund legt sie in dem vorhandenen imperative_PLs/fortranVerzeichnis ab.

Stellen Sie sich das renamestattdessen vor, und das Verhalten scheint verständlicher zu sein.

BowlOfRed
quelle
7

mvist eigentlich renameunter der Decke.

Wenn Sie eine Datei in eine andere Datei verschieben, wird mvdavon ausgegangen, dass Sie wissen, was Sie tun, und die Zieldatei überschreiben.

Wenn Sie ein Verzeichnis in ein anderes Verzeichnis verschieben, wird mvdavon ausgegangen , dass Sie den Basisnamen Ihres ursprünglichen Verzeichnisses beibehalten und im Zielverzeichnis erstellen möchten. Wenn auf der Zielseite noch kein Verzeichnis mit diesem Namen vorhanden ist oder wenn ein Verzeichnis mit diesem Namen vorhanden ist, das jedoch leer ist, ist der Vorgang erfolgreich.

Wenn das Zielverzeichnis jedoch bereits vorhanden und nicht leer ist, handelt es sich nicht mehr renameum ein rekursives Entfernen von Dateien und Verzeichnissen. renameist nicht dafür ausgelegt, also schlägt es fehl, mvgeht nicht weiter, da davon ausgegangen wird, dass Sie es nicht wollten, und schlägt auch fehl.

jlliagre
quelle
Vielen Dank. Ist rmAnruf rmdir()neben rename()?
Tim
1
@ Tim: rmruft nie an rename(). Aber es ruft auf, rmdir()wenn die -rOption gegeben wird.
Guntram Blohm unterstützt Monica
@ Gun: Mein Tippfehler. Ich meinte mvstatt rm.
Tim
1
mvAufrufe rmdir()nur, wenn das Quell- und das Zieldateisystem unterschiedlich sind. Ein Grund ist, dass nicht mehr dieselbe Inode einen neuen Pfad hat.
Jlliagre
3

Die Fehlermeldung beim Wechseln zwischen Dateisystemen ist etwas ausführlicher:

# mv a/foo b/bar
mv: inter-device move failed: 'a/foo' to 'b/bar/foo'; unable to remove target: Directory not empty

Es wird also nicht versucht, Verzeichnisse zusammenzuführen, wie Sie es zu erwarten scheinen, sondern das Ziel wird entfernt, bevor die Quelle umbenannt wird. Das Entfernen für Verzeichnisse funktioniert nur, wenn es leer ist.

In Bezug auf Systemaufrufe ist es innerhalb desselben Dateisystems einfach rename()

rename("a/foo", "a/bar/foo")            = -1 ENOTEMPTY (Directory not empty)

Beim Wechsel zwischen Dateisystemen wird zunächst rename()dieser Fall erkannt und ein einfacher Versuch unternommen rmdir().

rename("a/foo", "b/bar/foo")            = -1 EXDEV (Invalid cross-device link)
rmdir("b/bar/foo")                      = -1 ENOTEMPTY (Directory not empty)

mvkönnte sich mehr anstrengen, will es aber nicht. ;)

Frostschutz
quelle
Vielen Dank. tut mvAnruf rmdir()? Ich habe versucht , ein mit strace -e trace=fileauf mv, rmdir()nicht kommen.
Tim
nur wenn Dateisystemgrenzen überschritten werden, sonst wird rename()es
wahrscheinlich