Jawaban:
Seperti @samiam telah menyatakan daftar dikembalikan kepada Anda dalam urutan semi-acak via readdir()
. Saya hanya akan menambahkan yang berikut ini.
Daftar yang dikembalikan adalah apa yang saya sebut urutan direktori. Pada sistem file yang lebih lama, urutannya sering kali urutan pembuatan yang entri file dalam tabel direktori ditambahkan. Tentu saja ada peringatan untuk ini, ketika entri direktori dihapus, entri ini kemudian didaur ulang, sehingga setiap file berikutnya yang disimpan akan menggantikan entri sebelumnya, sehingga pesanan tidak akan lagi hanya didasarkan pada waktu pembuatan.
Pada sistem file modern di mana struktur data direktori didasarkan pada pohon pencarian atau tabel hash, urutannya praktis tidak dapat diprediksi.
Menyodok file yang dibuat ketika Anda menjalankan perintah sentuh Anda mengungkapkan inode berikut ditugaskan.
$ 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
Jadi kita dapat melihat bahwa ekspansi brace yang digunakan oleh sentuhan menciptakan nama file dalam urutan abjad dan mereka diberi nomor inode berurutan saat ditulis ke HDD. (Namun itu tidak mempengaruhi urutan dalam direktori.)
Menjalankan tar
perintah Anda berkali-kali tampaknya menunjukkan bahwa ada urutan ke daftar, karena menjalankannya berkali-kali menghasilkan daftar yang sama setiap kali. Di sini saya telah menjalankannya 100 kali dan kemudian membandingkan prosesnya dan semuanya identik.
$ 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
$
Jika kita secara strategis menghapus katakan dir/e
dan kemudian menambahkan file baru dir/ee
kita dapat melihat bahwa file baru ini telah mengambil tempat yang dir/e
diduduki sebelumnya dalam tabel entri direktori.
$ rm dir/e
$ touch dir/ee
Sekarang mari kita menjaga output dari salah satu for
loop di atas, hanya yang pertama.
$ mv run1 r1A
Sekarang jika kita menjalankan kembali for
loop yang akan menjalankan tar
perintah 100 kali lagi, dan bandingkan run kedua ini dengan yang sebelumnya:
$ 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
...
Kami perhatikan bahwa dir/ee
telah dir/e
terjadi di tabel direktori.
readdir()
pada dasarnya Ketika tar mengetahui file apa yang ada di direktori, ia langsung meminta kernel untuk daftar file yang opendir()
diikuti oleh readdir()
. readdir()
tidak mengembalikan file dalam urutan tertentu; cara file dipesan tergantung pada sistem file yang digunakan oleh kernel Linux.
Sayangnya, tidak ada opsi untuk tar
mengurutkan file dalam subdirektori (menambahkan satu dibiarkan sebagai latihan untuk pembaca).
f_op->iterate
Panggilan yang readdir()
akhirnya disaring oleh glibc ke getdents()
dipetakan ke implementasi spesifik sistem file. Saya tidak dapat melihat apa pun di tingkat yang lebih tinggi yang menata ulang dirent
penerapan fs kembali.
stat --printf='%i\t-- %n\n' * | sort -n | sed 's/.*\t-- //'