Warum dauert das Verschieben einiger Dateien in einem Ordner länger als das Verschieben des gesamten Ordners?

21

Ich habe Millionen von Bildern auf meinem Ubuntu-Cloud-Server. Wenn ich mit dem mvBefehl einen vollständigen Ordner mit 12 Millionen Bildern verschiebe , geschieht dies fast augenblicklich. Allerdings, wenn ich mvnur Bilder (nicht den Ordner) dann dauert es einige Zeit. Gibt es eine Möglichkeit, alle Bilder so schnell wie Ordner zu verschieben?

Folgendes passiert gerade:

  1. src ordner hat 12 millionen bilder und ich verschiebe diese in den dst ordner mit

    $ mv  src ../dst
    

    Passiert sofort

  2. Im src-Ordner gehe ich folgendermaßen vor, um:

    find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/ {} +
    

    Dies dauert einige Zeit.

Gibt es eine Möglichkeit, den zweiten Prozess zu beschleunigen?

sankit
quelle
1
Keine Lösung - aber zur Verdeutlichung: cmd2 muss langsamer sein als cmd1, da es find verwendet und dann den Move für das Ergebnis ausführt. Dies kann niemals so schnell sein wie eine direkte Bewegung ohne einen Vorfindungsprozess.
Dufte
befindet sich wahrscheinlich dstin einer Partition, wohingegen ../../dstsich auf einer anderen befindet.
Phuclv
Wie geschrieben scheint dies nicht einmal ein gültiger Aufruf von find zu sein. Es fehlt ein {}Argument, in dem die Dateinamen erweitert würden.
R ..
Ich habe eine Bearbeitung eingereicht, mit der der Titel geändert, der Verweis auf "Bilder" entfernt und durch den Kern der Sache ersetzt wird - es werden einzelne Dateien verschoben, im Gegensatz zum Verschieben des gesamten Ordners. Ich hoffe, es wird von jemandem mit dem Repräsentanten akzeptiert, der es tut.
Monty Harder
1
Es ist kein gültiger Aufruf von find. find ... -exec mv -t ../../dst/ {} \;würde mveinmal pro Datei anrufen ; find ... -exec mv -t ../../dest {} +Es wäre viel schneller, so viele Dateien wie möglich pro Aufruf zu kopieren, aber immer noch nicht so schnell, wie das von dadexix86 erklärte Verzeichnis selbst zu verschieben .
Chepner

Antworten:

50

TL; DR : Nein

Für eine kleinere Anzahl von Dateien würden Sie findaber auch in diesem vereinfachten und kleineren Fall nicht brauchen , wenn Sie nur

mv *.jpg ../../dst/

Es dauert länger, als das gesamte Verzeichnis auf einmal zu verschieben.


Warum? Der Punkt ist zu verstehen, was mvtut.

Verschiebt kurz gesagt mveine Zahl (die ein Verzeichnis oder eine Datei kennzeichnet) von einem Inode (dem Verzeichnis, in dem sie enthalten ist) in einen anderen, und diese Indizes werden im Journal des Dateisystems oder in der FAT (falls das Dateisystem) aktualisiert ist so implementiert).

Befinden sich Quelle und Ziel im selben Dateisystem, gibt es keine tatsächliche Datenverschiebung. Sie ändert lediglich die Position und den Punkt, an dem sie angehängt sind.

Wenn Sie also mv ein Verzeichnis haben, führen Sie diesen Vorgang einmal aus .

Wenn Sie jedoch 1 Million Dateien verschieben, führen Sie diesen Vorgang 1 Million Mal durch .

Um Ihnen ein praktisches Beispiel zu geben: Sie haben einen Baum mit vielen Ästen. Insbesondere gibt es einen Knoten, an den 1 Million Zweige angeschlossen sind.
Um diese Zweige abzuschneiden und an einen anderen Ort zu verschieben, können Sie sie entweder einzeln abschneiden, sodass Sie 1 Million Schnitte ausführen, oder Sie schneiden direkt vor dem Knoten, sodass Sie nur einen Schnitt ausführen (dies ist der Unterschied zwischen dem Verschieben der Dateien und das Verzeichnis).

dadexix86
quelle
4
Sie sollten einschließen, dass ein mvin demselben Dateisystem nur ein Umschreiben des Inhaltsverzeichniseintrags ist.
Videonauth
Ich bin mir nicht sicher, ob ich verstehe, was Sie mit TOC meinen. Soweit ich weiß, gibt es keine Tabelle in ext-Dateisystemen oder NTFS oder btrfs und so weiter. FAT hat eine Tabelle (aus der der Name stammt), aber ext speichert beispielsweise Namen und Blöcke sowie Eltern, Kinder und andere Informationen in den Inodes. Wenn Sie mir einen Verweis geben können, in dem erklärt wird, woher ext FS das Inhaltsverzeichnis hat und wofür es verwendet wird, lese und aktualisiere ich die Antwort gern :)
dadexix86
10
Äh. mv *.jpgdürfte bei 12 Millionen Dateien scheitern, weshalb er find verwendet. Die meisten Unixe, einschließlich Linux, haben meines Erachtens (es sei denn, jemand hat sie in den letzten 5 bis 10 Jahren geändert) eine begrenzte maximale Länge der Befehlszeile. Ich denke, es war lange Zeit 64K für Linux. Die gleiche Grenze gilt für Umgebungsvariablen, da bin ich mir ziemlich sicher.
Zan Lynx
1
Beim Verschieben einer Datei geht es mehr um das Verschieben ihres Namens . Unix-ähnliche Verzeichniseinträge enthalten einen Dateinamen und eine Inode-Nummer, die im Grunde genommen einen Zeiger auf den Rest der Metadaten darstellt. Ein Verzeichnis ist nur eine spezielle Art einer Datei. Der Inode selbst enthält nicht die eigentlichen Daten der Datei, sondern zeigt nur darauf. Es ist also etwas irreführend zu sagen, dass etwas von einem Inode verschoben wird. Andererseits beziehen sich Dateisystemjournale normalerweise auf einen Typ eines Metadatenprotokolls, das hauptsächlich für Absturzsicherungen verwendet wird.
ilkkachu
1
Natürlich ist die Terminologie hier nicht das Wichtigste. Das Wichtige ist genau das, was Sie gesagt haben: Innerhalb eines Dateisystems muss eine Bewegung nur die Metadaten berühren. Von einem Dateisystem zu einem anderen gibt es keine Verknüpfung, und alle Dateien müssen nacheinander verschoben (neu erstellt) werden, einschließlich ihres Inhalts. In diesem Fall spielt es keine Rolle, ob das gesamte Verzeichnis oder nur die darin enthaltenen Dateien verschoben werden.
Ilkkachu
13

Es wird immer noch langsam sein, da das Dateisystem, wie bereits erwähnt, jeden Dateinamen an seinen neuen Speicherort verlinken muss.

Sie können es jedoch von dem, was Sie jetzt haben, beschleunigen.

Ihr Suchbefehl führt die Ausführung für jede Datei einmal aus. So wird der mvBefehl 12 Millionen Mal für 12 Millionen Dateien gestartet. Dies kann auf zwei Arten verbessert werden.

  • Fügen Sie am Ende ein Pluszeichen hinzu:
    find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/ +
    Überprüfen Sie die Manpage, um sicherzustellen, dass sie in Ihrer Version von unterstützt wird find. Der Effekt sollte darin bestehen, eine Reihe von mvBefehlen mit so vielen Dateinamen auszuführen, wie auf jede Befehlszeile passen.

  • Verwenden Sie findund xargszusammen.
    find -maxdepth 1 -name '*.jpg' -print0 | xargs -0 mv -t ../../dst/
    Das -print0wird NUL, auch bekannt als Null-Byte, verwenden, um die Dateinamen zu trennen. Dieses Plus xargs -0behebt alle Probleme, xargsdie ansonsten mit Leerzeichen in Dateinamen auftreten könnten. Der xargsBefehl liest die Liste der Dateinamen aus dem findBefehl und führt den mvBefehl für so viele Dateinamen aus, wie passen.

Zan Lynx
quelle
7

Ihre Verwirrung rührt von der Dateisystemabstraktion her, die Sie glauben lässt, dass ein Ordner Dateien und andere Ordner in einer baumartigen Weise enthält. Dies ist jedoch nicht der Fall: Alle Dateien und Verzeichnisse in einem Dateisystem befinden sich auf derselben Ebene und werden abhängig von der Implementierung mit einer Reihe von Nummern gekennzeichnet. Verzeichnisse sind nur spezielle Dateien, die Listen anderer Dateien enthalten.

Wenn Sie Dateien in einem Dateisystem "verschieben", werden die eigentlichen Dateien nirgendwo abgelegt. Stattdessen werden Listen in Verzeichnissen aktualisiert, um die Änderung widerzuspiegeln.

mv src ../dstVerschiebt einen einzelnen Listeneintrag von Verzeichnis .zu Verzeichnis ../dst, so ist es schnell.

find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/muss Millionen von Einträgen verschieben, also ist es langsamer. Es kann möglicherweise beschleunigt werden, wenn Sie mvnur einmal und nicht einmal pro Datei aufrufen , und der mvBefehl selbst kann so optimiert werden, dass mehrere Verzeichniseinträge in einem Schritt verschoben werden. Es gibt jedoch keine Möglichkeit, ihn so schnell wie beim Verschieben eines einzelnen Verzeichnisses zu gestalten .

Dmitry Grigoryev
quelle
4

Eine vereinfachte Antwort

Das Verschieben einer Datei erfolgt in 3 Schritten:

  • Füge () einen Link zu der Datei zur Inode-Liste des Zielordners hinzu
  • Überprüfen Sie, ob der Link erfolgreich hinzugefügt wurde
  • Entfernen Sie () den Link aus der Liste der Inodes des Quellordners, wenn die Prüfung oben erfolgreich war.

Dieser Vorgang ist für eine Datei oder einen Ordner identisch.
und offensichtlich ist dies für 1 Datei 100 schneller als für 100 Dateien.

man link is the add ()
man unlinkis the remove () verwendet
mvnur die beiden obigen Befehle und fügt eine dazwischen liegende Prüfung hinzu, um Datenverlust zu vermeiden.


quelle
1
Nun, es gibt auch umbenennen ().
Ilkkachu