Wie wird die Reihenfolge festgelegt, in der tar auf Dateien angewendet wird?

15
$ touch dir/{{1..8},{a..p}}
$ tar cJvf file.tar.xz dir/
dir/
dir/o
dir/k
dir/b
dir/3
dir/1
dir/i
dir/7
dir/4
dir/e
dir/a
dir/g
dir/2
dir/d
dir/5
dir/8
dir/c
dir/n
dir/f
dir/h
dir/6
dir/l
dir/m
dir/j
dir/p

Ich hätte erwartet, dass es alphabetisch ist. Aber anscheinend ist es nicht. Wie lautet hier die Formel?

John
quelle

Antworten:

14

Wie @samiam angegeben hat, wird die Liste in einer halbzufälligen Reihenfolge über an Sie zurückgesendet readdir(). Ich füge nur Folgendes hinzu.

Die zurückgegebene Liste würde ich als Verzeichnisreihenfolge bezeichnen. Bei älteren Dateisystemen entspricht die Reihenfolge oft der Erstellungsreihenfolge, in der die Dateieinträge in der Tabelle des Verzeichnisses hinzugefügt wurden. Dies hat natürlich eine Einschränkung: Wenn ein Verzeichniseintrag gelöscht wird, wird dieser Eintrag wiederverwendet, sodass alle nachfolgenden Dateien, die gespeichert werden, den vorherigen Eintrag ersetzen, sodass die Reihenfolge nicht mehr ausschließlich auf der Erstellungszeit basiert.

In modernen Dateisystemen, in denen Verzeichnisdatenstrukturen auf einem Suchbaum oder einer Hash-Tabelle basieren, ist die Reihenfolge praktisch unvorhersehbar.

Beispiele

Das Stöbern in den Dateien, die beim Ausführen Ihres Touch-Befehls erstellt wurden, zeigt, dass die folgenden Inodes zugewiesen wurden.

$ touch dir/{{1..8},{a..p}}
$ stat --printf="%n -- %i\n" dir/*
dir/1 -- 10883235
dir/2 -- 10883236
dir/3 -- 10883242
dir/4 -- 10883243
dir/5 -- 10883244
dir/6 -- 10883245
dir/7 -- 10883246
dir/8 -- 10883247
dir/a -- 10883248
dir/b -- 10883249
dir/c -- 10883250
dir/d -- 10883251
dir/e -- 10883252
dir/f -- 10883253
dir/g -- 10883254
dir/h -- 10883255
dir/i -- 10883256
dir/j -- 10883299
dir/k -- 10883302
dir/l -- 10883303
dir/m -- 10883311
dir/n -- 10883424
dir/o -- 10883426
dir/p -- 10883427

So können wir sehen, dass die von touch verwendete geschweifte Klammer die Dateinamen in alphabetischer Reihenfolge erstellt und ihnen beim Schreiben auf die Festplatte fortlaufende Inode-Nummern zugewiesen werden. (Dies hat jedoch keinen Einfluss auf die Reihenfolge im Verzeichnis.)

Wenn Sie Ihren tarBefehl mehrmals ausführen, scheint dies darauf hinzudeuten, dass die Liste eine Reihenfolge aufweist, da die mehrfache Ausführung jedes Mal dieselbe Liste ergibt. Hier habe ich es 100 Mal ausgeführt und dann die Läufe verglichen und sie sind alle identisch.

$ for i in {1..100};do tar cJvf file.tar.xz dir/ > run${i};done
$ for i in {1..100};do cmp run1 run${i};done
$ 

Wenn wir beispielsweise strategisch löschen dir/eund dann eine neue Datei hinzufügen, dir/eekönnen wir sehen, dass diese neue Datei den Platz dir/eeingenommen hat, den sie zuvor in der Verzeichniseintragstabelle eingenommen hat.

$ rm dir/e
$ touch dir/ee

Lassen Sie uns nun die Ausgabe von einer der forobigen Schleifen, nur der ersten , behalten .

$ mv run1 r1A

Wenn wir nun die forSchleife, die den tarBefehl 100 Mal ausführt, erneut ausführen und diesen zweiten Lauf mit dem vorherigen vergleichen:

$ sdiff r1A run1
dir/                                dir/
...
dir/c                               dir/c
dir/f                               dir/f
dir/e                             | dir/ee
dir/o                               dir/o
dir/2                               dir/2
...

Wir stellen fest, dass dies in der Verzeichnistabelle dir/eestattgefunden hat dir/e.

slm
quelle
Wow, das ist wirklich eine großartige Antwort. Kann ich in einem vorgegebenen Verzeichnis in welcher Reihenfolge tar seine Unterelemente verarbeiten? Ich bin nicht wirklich zuversichtlich, aber wie sieht das für Sie aus? stat --printf='%i\t-- %n\n' * | sort -n | sed 's/.*\t-- //'
John
2
Ich denke, es ist abhängig vom Dateisystem. Ich kann mir ein Dateisystem vom Typ btree vorstellen, das sie nach der Reihenfolge des Datei-Hash sortiert, oder so (ich habe das Gefühl, das alte ReiserFS ordnet sie anders, da dieses Dateisystem dynamisch Inodes erstellt)
samiam
1
@samiam - Richtig, diese Antwort behauptet, dass die 'Verzeichnisreihenfolge' die 'Erstellungsreihenfolge' ist, in der die Dateieinträge in der Tabelle des Verzeichnisses hinzugefügt wurden, und zeigt dann selbst Fragmente des Inhalts der TAR-Datei an, die anzeigen, dass dies nicht zutrifft. Viele Dateisysteme, einschließlich der aktuellen Linux ext * -Dateisysteme, verwenden in ihren Verzeichnisstrukturen Verzeichnisbäume und / oder Hashes, keine einfachen sequentiellen Tabellen wie einige ältere Dateisysteme.
Michał Politowski
3
@ John ls -for ls -Uorfind -maxdepth 1
1
@ John die -fFlagge stammt aus dem alten Unix. Sein Zweck war es, schnell zu sein. Es deaktivierte das Sortieren, das Überspringen von Punktedateien und ein paar andere Dinge. Die -UFlagge ist eine GNU-Innovation, mit der Sie die Sortierung ohne weitere Nebenwirkungen deaktivieren können.
8

readdir()Grundsätzlich. Wenn tar herausfindet, welche Dateien sich in einem Verzeichnis befinden, fragt er den Kernel direkt nach einer Dateiliste über opendir()gefolgt von readdir(). readdir()gibt die Dateien nicht in einer bestimmten Reihenfolge zurück; Die Reihenfolge der Dateien hängt vom Dateisystem ab, das vom Linux-Kernel verwendet wird.

Leider ist dies keine Option tar, um Dateien in Unterverzeichnissen zu sortieren (das Hinzufügen einer Option wird dem Leser als Übung überlassen).

samiam
quelle
1
Ich habe mich gefragt, ob es sie basierend auf dem Wert ihres Inodes abruft.
SLM
1
@slm Der f_op->iterateAufruf, den glibc readdir()schließlich nach via filtert, getdents()wird einer dateisystemspezifischen Implementierung zugeordnet. Ich kann auf einer höheren Ebene nichts sehen, was die Ergebnisse der direntImplementierung von fs neu ordnet .
Matt
@slm Nein, ich habe noch nie von einem Dateisystem gehört, bei dem der Inode-Wert einen Einfluss auf die Verzeichnisreihenfolge hat.
Gilles 'SO - hör auf böse zu sein'