Answers:
正如@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/ee
已dir/e
取代。
readdir()
基本上。当焦油发现哪些文件是在一个目录,它直接询问一个文件列表通过内核opendir()
之后readdir()
。 readdir()
不以任何特定顺序返回文件;文件的排序方式取决于Linux内核使用的文件系统。
a,在那里,不能tar
对子目录中的文件进行排序(添加一个作为练习供读者阅读)。
f_op->iterate
glibc readdir()
最终过滤到via 的调用getdents()
被映射到特定于文件系统的实现。我看不到更高层次上重新排序dirent
fs实现返回值的任何内容。
stat --printf='%i\t-- %n\n' * | sort -n | sed 's/.*\t-- //'