如何确定tar在文件上的工作顺序?


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

我希望它是按字母顺序排列的。但显然不是。公式是什么?

Answers:


14

正如@samiam所说,该列表会以半随机顺序通过返回给您readdir()。我将添加以下内容。

返回的列表就是我所说的目录顺序。在较旧的文件系统上,该顺序通常是添加目录表中文件条目的创建顺序。当然有一个警告,删除目录条目后,该条目将被回收,因此存储的所有后续文件都将替换先前的条目,因此不再仅基于创建时间来排序。

在目录数据结构基于搜索树或哈希表的现代文件系统上,顺序实际上是不可预测的。

例子

在您运行touch命令时查看创建的文件,就会发现分配了以下inode。

$ 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

因此,我们可以看到touch所使用的大括号扩展名是按字母顺序创建文件名的,因此在写入HDD时会为其分配顺序的inode编号。(但是,这不会影响目录中的顺序。)

tar多次运行您的命令似乎表明该列表存在顺序,因为多次运行它每次都会产生相同的列表。在这里,我已经运行了100次,然后比较了运行,它们都是相同的。

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

如果我们从战略上删除了say dir/e然后添加了新文件,dir/ee我们可以看到该新文件已取代dir/e了目录条目表中先前占据的位置。

$ rm dir/e
$ touch dir/ee

现在,让我们保留for上面循环之一的输出,只是第一个循环的输出。

$ mv run1 r1A

现在,如果我们重新运行for循环,该循环将tar再次运行该命令100次,并将第二次运行与上一次运行进行比较:

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

我们注意到在目录表中dir/eedir/e取代。


哇,这真的是一个很好的答案。给定目录,我有什么办法可以查看tar处理子项的顺序是什么?我对此并不十分有信心,但是以下内容对您有何感想?stat --printf='%i\t-- %n\n' * | sort -n | sed 's/.*\t-- //'
约翰

2
我认为这取决于文件系统。我可以想象一个btree类型的文件系统根据文件哈希或类似的顺序对其进行排序(我感觉到旧的ReiserFS对它们的排序有所不同,因为该文件系统动态创建了inode)
samiam 2014年

1
@samiam-对,这个答案声称“目录顺序”是“添加目录表中文件条目的创建顺序”,然后它本身显示了tar文件内容的片段,表明这是不正确的。许多文件系统(包括当前的Linux ext *文件系统)在其目录结构中使用树和/或哈希,而不是像某些较旧的文件系统那样使用简单的顺序表。
米哈尔Politowski

3
@约翰ls -fls -Ufind -maxdepth 1

1
@John -f标志来自古老的Unix。其目的是要快。它禁用了排序,跳过点文件以及其他一些功能。该-U标志是GNU的一项创新功能,它使您可以禁用排序而没有任何其他副作用。

8

readdir()基本上。当焦油发现哪些文件是在一个目录,它直接询问一个文件列表通过内核opendir()之后readdir()readdir()不以任何特定顺序返回文件;文件的排序方式取决于Linux内核使用的文件系统。

a,在那里,不能tar对子目录中的文件进行排序(添加一个作为练习供读者阅读)。


1
我想知道是否根据它们的inode值检索它们?
slm

1
@slm f_op->iterateglibc readdir()最终过滤到via 的调用getdents()被映射到特定于文件系统的实现。我看不到更高层次上重新排序direntfs实现返回值的任何内容。
马特

@slm不,我从未听说过文件系统的inode值会影响目录顺序。
吉尔(Gilles)'所以
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.