Comment est déterminé l'ordre dans lequel tar fonctionne sur les fichiers?

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

Je me serais attendu à ce que ce soit alphabétique. Mais apparemment ce n'est pas le cas. Quelle est la formule ici?

John
la source

Réponses:

14

Comme @samiam l' a déclaré, la liste vous est retournée dans un ordre semi-aléatoire via readdir(). Je vais juste ajouter ce qui suit.

La liste renvoyée est ce que j'appellerais l'ordre du répertoire. Sur les anciens systèmes de fichiers, l'ordre est souvent l'ordre de création auquel les entrées de fichier dans la table du répertoire ont été ajoutées. Il y a bien sûr une mise en garde à cela, lorsqu'une entrée de répertoire est supprimée, cette entrée est ensuite recyclée, de sorte que tous les fichiers suivants qui sont stockés remplaceront l'entrée précédente, de sorte que l'ordre ne sera plus basé uniquement sur le temps de création.

Sur les systèmes de fichiers modernes où les structures de données de répertoire sont basées sur une arborescence de recherche ou une table de hachage, l'ordre est pratiquement imprévisible.

Exemples

Piquer les fichiers créés lorsque vous exécutez votre commande tactile révèle que les inodes suivants ont été attribués.

$ 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

Ainsi, nous pouvons voir que l'expansion de l'accolade utilisée par le toucher crée les noms de fichiers par ordre alphabétique et donc des numéros d'inode séquentiels leur sont attribués lorsqu'ils sont écrits sur le disque dur. (Cela n'influence cependant pas l'ordre dans le répertoire.)

L'exécution de votre tarcommande plusieurs fois semble indiquer qu'il existe un ordre dans la liste, car son exécution multiple génère la même liste à chaque fois. Ici, je l'ai couru 100 fois, puis j'ai comparé les courses et elles sont toutes identiques.

$ 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
$ 

Si nous supprimons stratégiquement say dir/epuis ajoutons un nouveau fichier, dir/eenous pouvons voir que ce nouveau fichier a pris la place qui dir/eoccupait auparavant dans le tableau des entrées des répertoires.

$ rm dir/e
$ touch dir/ee

Maintenant, gardons la sortie de l'une des forboucles ci-dessus, juste la 1ère.

$ mv run1 r1A

Maintenant, si nous réexécutons la forboucle qui exécutera à nouveau la tarcommande 100 fois, et comparons cette deuxième exécution avec la précédente:

$ 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
...

On remarque que cela dir/eea pris dir/eplace dans la table des répertoires.

slm
la source
Wow, c'est vraiment une excellente réponse. Étant donné un répertoire, existe-t-il un moyen pour moi de voir l'ordre dans lequel tar traitera ses sous-éléments? Je ne suis pas vraiment confiant à ce sujet, mais que pensez-vous de ce qui suit? stat --printf='%i\t-- %n\n' * | sort -n | sed 's/.*\t-- //'
John
2
Je pense que cela dépend du système de fichiers. Je peux imaginer un système de fichiers de type btree les triant en fonction de l'ordre du hachage de fichier ou de certains autres (j'ai le sentiment que l'ancien ReiserFS les commande différemment, car ce système de fichiers crée dynamiquement des inodes)
samiam
1
@samiam - à droite, cette réponse affirme que l '«ordre du répertoire» est «l'ordre de création auquel les entrées de fichier dans la table du répertoire ont été ajoutées», puis elle-même montre des fragments du contenu du fichier tar montrant que ce n'est pas vrai. De nombreux systèmes de fichiers, y compris les systèmes de fichiers Linux ext * actuels, utilisent des arborescences et / ou des hachages dans leurs structures de répertoires, pas de simples tables séquentielles comme certains systèmes de fichiers plus anciens.
Michał Politowski
3
@John ls -for ls -Uorfind -maxdepth 1
1
@John le -fdrapeau vient de l'ancien Unix. Son but était d'être rapide. Il a désactivé le tri, l'omission des fichiers dot et quelques autres choses. Le -Udrapeau est une innovation GNU qui vous permet de désactiver le tri sans aucun autre effet secondaire.
8

readdir()fondamentalement. Lorsque tar découvre quels fichiers se trouvent dans un répertoire, il demande directement au noyau une liste de fichiers via opendir()suivi de readdir(). readdir()ne renvoie pas les fichiers dans un ordre particulier; la façon dont les fichiers sont ordonnés dépend du système de fichiers utilisé par le noyau Linux.

Là, hélas, il n'y a pas d'option pour tartrier les fichiers dans les sous-répertoires (en ajouter un est laissé comme exercice pour le lecteur).

samiam
la source
1
Je me demandais s'il les récupère en fonction de la valeur de leur inode?
slm
1
@slm L' f_op->iterateappel que la glibc readdir()finit par filtrer vers via getdents()est mappé sur une implémentation spécifique au système de fichiers. Je ne vois rien à un niveau supérieur qui réorganise le direntretour de l'implémentation fs.
Matt
@slm Non, je n'ai jamais entendu parler d'un système de fichiers où la valeur d'inode aurait une influence sur l'ordre des répertoires.
Gilles 'SO- arrête d'être méchant'