Respostas:
Como @samiam afirmou, a lista é retornada a você em uma ordem semi-aleatória via readdir()
. Vou apenas adicionar o seguinte.
A lista retornada é o que eu chamaria de ordem de diretório. Em sistemas de arquivos mais antigos, a ordem geralmente é a ordem de criação em que as entradas de arquivo na tabela do diretório foram adicionadas. Obviamente, existe uma ressalva: quando uma entrada de diretório é excluída, essa entrada é reciclada; portanto, todos os arquivos subsequentes armazenados substituem a entrada anterior; portanto, o pedido não será mais baseado apenas no tempo de criação.
Nos sistemas de arquivos modernos em que as estruturas de dados do diretório são baseadas em uma árvore de pesquisa ou tabela de hash, a ordem é praticamente imprevisível.
Ao cutucar os arquivos criados quando você executa o comando touch, os seguintes inodes foram atribuídos.
$ 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
Assim, podemos ver que a expansão de braçadeira usada pelo toque cria os nomes dos arquivos em ordem alfabética e, portanto, eles recebem números de inodos seqüenciais quando gravados no HDD. (Isso, no entanto, não influencia a ordem no diretório.)
Executar seu tar
comando várias vezes parece indicar que há um pedido para a lista, uma vez que executá-lo várias vezes produz a mesma lista a cada vez. Aqui eu executei 100 vezes e depois comparei as execuções e são todas idênticas.
$ 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
$
Se excluirmos estrategicamente o say dir/e
e depois adicionarmos um novo arquivo dir/ee
, podemos ver que esse novo arquivo ocupou o lugar que dir/e
ocupava anteriormente na tabela de entradas de diretórios.
$ rm dir/e
$ touch dir/ee
Agora vamos manter a saída de um dos for
loop acima, apenas o primeiro.
$ mv run1 r1A
Agora, se executarmos novamente o for
loop que executará o tar
comando 100 vezes novamente e compararemos a segunda execução com a anterior:
$ 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
...
Notamos que dir/ee
tomou dir/e
's lugar na tabela de diretórios.
readdir()
basicamente. Quando o tar descobre quais arquivos estão em um diretório, ele solicita diretamente ao kernel uma listagem de arquivos via opendir()
seguido por readdir()
. readdir()
não retorna os arquivos em nenhuma ordem específica; a maneira como os arquivos são ordenados depende do sistema de arquivos que está sendo usado pelo kernel do Linux.
Infelizmente, não existe uma opção para tar
classificar arquivos em subdiretórios (a adição de um é deixada como um exercício para o leitor).
f_op->iterate
chamada que a glibc readdir()
eventualmente filtra para via getdents()
é mapeada para uma implementação específica do sistema de arquivos. Não consigo ver nada em um nível superior que reordene os dirent
retornos da implementação do fs.
stat --printf='%i\t-- %n\n' * | sort -n | sed 's/.*\t-- //'