Joh*_*ohn 20 linux tar gnu coreutils
$ 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
Run Code Online (Sandbox Code Playgroud)
我原以为它是按字母顺序排列的。但显然不是。这里的公式是什么?
slm*_*slm 18
正如@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
Run Code Online (Sandbox Code Playgroud)
所以我们可以看到 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
$
Run Code Online (Sandbox Code Playgroud)
如果我们策略性地删除 saydir/e然后添加一个新文件,dir/ee我们可以看到这个新文件已经取代了dir/e之前在目录条目表中占据的位置。
$ rm dir/e
$ touch dir/ee
Run Code Online (Sandbox Code Playgroud)
现在让我们保留for上面循环之一的输出,只是第一个。
$ mv run1 r1A
Run Code Online (Sandbox Code Playgroud)
现在,如果我们重新运行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
...
Run Code Online (Sandbox Code Playgroud)
我们注意到dir/ee已经dir/e在目录表中占据了位置。
readdir()基本上。当 tar 找出目录中的文件时,它会直接通过opendir()后跟readdir(). readdir()不以任何特定顺序返回文件;文件的排序方式取决于 Linux 内核使用的文件系统。
唉,这不是tar对子目录中的文件进行排序的选项(添加一个留给读者作为练习)。