Как определяется порядок, в котором tar работает с файлами?

15
$ 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

Я ожидал бы, что это будет в алфавитном порядке. Но, видимо, это не так. Какая здесь формула?

Джон
источник

Ответы:

14

Как заявил @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место в таблице каталогов.

SLM
источник
Вау, это действительно отличный ответ. Имея какой-либо каталог, могу ли я узнать, в каком порядке tar будет обрабатывать его подэлементы? Я не совсем уверен в этом, но как к вам относится следующее? stat --printf='%i\t-- %n\n' * | sort -n | sed 's/.*\t-- //'
Джон
2
Я думаю, что это зависит от файловой системы. Я могу представить себе файловую систему типа btree, сортирующую их по порядку хэша файла или тому подобное (у меня есть ощущение, что старый ReiserFS упорядочивает их по-разному, поскольку эта файловая система динамически создает inode)
samiam
1
@samiam - верно, этот ответ утверждает, что «порядок каталога» - это «порядок создания, в который были добавлены записи файла в таблице каталога», а затем он сам показывает фрагменты содержимого файла tar, показывая, что это не так. Многие файловые системы, включая современные файловые системы Linux ext *, используют деревья и / или хэши в своих структурах каталогов, а не простые последовательные таблицы, как некоторые старые файловые системы.
Михал Политовски
3
@Джон ls -fили ls -Uилиfind -maxdepth 1
1
@ Джон - это -fфлаг древнего Unix. Его целью было быть быстрым. Это отключило сортировку, пропуск точечных файлов и некоторые другие вещи. -UФлаг является новшеством GNU , которая позволяет отключить сортировку без каких - либо других побочных эффектов.
8

readdir()в принципе. Когда tar выясняет, какие файлы находятся в каталоге, он напрямую запрашивает ядро ​​для получения списка файлов, opendir()а затем readdir(). readdir()не возвращает файлы в каком-либо определенном порядке; порядок упорядочения файлов зависит от файловой системы, используемой ядром Linux.

Там, увы, нет возможности tarсортировать файлы в подкаталогах (добавление одного из них остается в качестве упражнения для читателя).

samiam
источник
1
Мне было интересно, если он извлекает их на основе значения их inode?
SLM
1
@slm f_op->iterateВызов, который glibc в readdir()конечном итоге фильтрует через via getdents(), сопоставляется с конкретной реализацией файловой системы. Я не вижу ничего на более высоком уровне, который переупорядочивает direntвозвращаемую реализацию fs.
Мэтт
@slm Нет, я никогда не слышал о файловой системе, в которой значение inode влияло бы на порядок каталогов.
Жиль "ТАК - перестань быть злым"