回答:
以下のよう@samiamは述べているリストは、経由セミランダムな順序であなたに返されますreaddir()
。以下を追加します。
返されるリストは、ディレクトリ順序と呼ばれるものです。古いファイルシステムでは、多くの場合、順序はディレクトリのテーブル内のファイルエントリが追加された作成順序です。もちろんこれには注意が必要です。ディレクトリエントリが削除されると、このエントリはリサイクルされるため、格納されている後続のファイルは前のエントリを置き換えるため、作成時間のみに基づいて順序はなくなります。
ディレクトリデータ構造が検索ツリーまたはハッシュテーブルに基づいている現代のファイルシステムでは、順序は実際には予測できません。
touchコマンドを実行したときに作成されたファイルを確認すると、次のiノードが割り当てられていることがわかります。
$ 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に書き込まれるときに連続したiノード番号が割り当てられることがわかります。(ただし、ディレクトリ内の順序には影響しません。)
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
上記のループの1つだけからの出力を保持しましょう。
$ mv run1 r1A
次に、再実行すると for
tar
コマンドを再度100回ループ実行し、この2回目の実行を前の実行と比較した場合:
$ 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()
基本的に。tarは、ディレクトリ内のファイルを見つけると、にopendir()
続いてを介してファイルリストをカーネルに直接要求しますreaddir()
。 readdir()
特定の順序でファイルを返しません。ファイルの順序は、Linuxカーネルが使用しているファイルシステムによって異なります。
悲しいかな、そこにtar
はサブディレクトリ内のファイルを並べ替えるオプションはありません(1つを追加することは読者の演習として残されています)。
f_op->iterate
glibcがreaddir()
最終的にviaにフィルタリングする呼び出しgetdents()
は、ファイルシステム固有の実装にマッピングされます。私dirent
はfs実装が返すs を並べ替えるより高いレベルでは何も見ることができません。
stat --printf='%i\t-- %n\n' * | sort -n | sed 's/.*\t-- //'