Как заявил @samiam , список возвращается вам в полуслучайном порядке через readdir()
. Я просто добавлю следующее.
Возвращенный список - это то, что я бы назвал порядком каталогов. В старых файловых системах этот порядок часто является порядком создания, в который были добавлены записи файла в таблице каталога. Это, конечно, предостережение: когда запись в каталоге удаляется, эта запись затем перерабатывается, поэтому любые последующие сохраненные файлы заменят предыдущую, поэтому порядок больше не будет зависеть только от времени создания.
В современных файловых системах, где структуры данных каталогов основаны на дереве поиска или хэш-таблице, порядок практически непредсказуем.
Примеры
Просмотр файлов, созданных при запуске вашей команды касания, показывает, что были назначены следующие 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, создает имена файлов в алфавитном порядке, и поэтому им присваиваются последовательные номера инодов при записи на жесткий диск. (Это, однако, не влияет на порядок в каталоге.)
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
место в таблице каталогов.
stat --printf='%i\t-- %n\n' * | sort -n | sed 's/.*\t-- //'
ls -f
илиls -U
илиfind -maxdepth 1
-f
флаг древнего Unix. Его целью было быть быстрым. Это отключило сортировку, пропуск точечных файлов и некоторые другие вещи.-U
Флаг является новшеством GNU , которая позволяет отключить сортировку без каких - либо других побочных эффектов.readdir()
в принципе. Когда tar выясняет, какие файлы находятся в каталоге, он напрямую запрашивает ядро для получения списка файлов,opendir()
а затемreaddir()
.readdir()
не возвращает файлы в каком-либо определенном порядке; порядок упорядочения файлов зависит от файловой системы, используемой ядром Linux.Там, увы, нет возможности
tar
сортировать файлы в подкаталогах (добавление одного из них остается в качестве упражнения для читателя).источник
f_op->iterate
Вызов, который glibc вreaddir()
конечном итоге фильтрует через viagetdents()
, сопоставляется с конкретной реализацией файловой системы. Я не вижу ничего на более высоком уровне, который переупорядочиваетdirent
возвращаемую реализацию fs.