Listar arquivos ordenados numericamente

108

Eu tenho vários arquivos de log1 a log164 .

Estou tentando LISTAR o diretório (classificado) em um terminal UNIX, mas as funções de classificação estão fornecendo apenas o formato assim:

home:logs Home$ ls -1 | sort
log1.gz
log10.gz
log100.gz
log101.gz
log102.gz
log103.gz
log104.gz
log105.gz
log106.gz
...etc

O que eu quero é

home:logs Home$ ls -1 | sort
log1.gz
log2.gz
log3.gz
log4.gz
log5.gz
log6.gz
log7.gz
...{more here}
log99.gz
log100.gz
log101.gz
log102.gz
...etc

Alguma sugestão do que eu poderia usar para fazer isso?

    
por Volker Siegel 09.03.2012 / 03:18

9 respostas

32
As chaves de% p_de%, bash , irão enumerá-las na ordem:

for file in log{1..164}.gz; do
    process "$file"
done
    
por 09.03.2012 / 03:29
228

Por que não usar o recurso ls embutido para este caso específico, a saber

-v natural sort of (version) numbers within text

Por exemplo, ls -1v log*

    
por 10.03.2012 / 17:05
40

Com o GNU ls (por exemplo, no Linux, Cygwin ou outros sistemas que tenham o GNU ls especificamente instalado):

ls -v

No zsh:

echo *(n)

Em outros shells:

echo log?.gz log??.gz log???.gz

Substitua echo por printf '%s\n' se você quiser cada nome de arquivo em uma linha separada.

Se você quiser também os metadados de arquivo ( ls -l ) e não tiver o GNU ls, será necessário chamar ls separadamente para cada nome de arquivo ou grupo de nomes de arquivo que você deseja ver em lexicographic ordem.

ls -ld log?.gz; ls -ld log??.gz; ls -ld log???.gz

Para evitar essas dificuldades, use zeros iniciais suficientes em seus nomes de arquivos para que a classificação lexicográfica seja amigável para os seres humanos ( log001.gz , etc).

    
por 12.03.2012 / 02:52
25

Embora a solução ls -1v seja certamente a mais legal neste caso específico, acho que é bom ter também uma que funcione com sort como na pergunta original, já que isso funciona também quando sua entrada não vem de% código%. Neste caso, você pode usar:

ls -1 | sort -n -k1.4

A opção ls diz ao ordenação para ordenar numericamente, e -n define a chave de ordenação para o primeiro campo (que é o nome completo do arquivo neste caso) a partir do quarto caractere até o último.

    
por 12.03.2012 / 13:41
17

O GNU sort (como disponível no Linux,) tem um modo de "ordenação de versão" que interpreta números dentro de não-números da maneira que você pede:

De man 1 sort :

    -V, --version-sort
           natural sort of (version) numbers within text

(Criando arquivos de teste vazios para listar:% touch log1.gz log2.gz log3.gz log99.gz log100.gz log101.gz log102.gz )

Seu exemplo, adicionando a opção -V (ou --version-sort ):

ls -1 log*.gz | sort -V
log1.gz
log2.gz
log3.gz
log99.gz
log100.gz
log101.gz
log102.gz
    
por 07.05.2014 / 00:18
6

se você usa Mac ou BSD, tente isto:

ls -1 *.jpg | sort -n
    
por 05.10.2016 / 09:26
3

Minha versão do Solaris não suporta ls -v (grrr). E a solução de classificação fornecida acima 1) requer conhecimento da posição dos dígitos no nome do arquivo e 2) não manipula coisas como números de versão com várias partes.

A abordagem abaixo é compatível com o Solaris, não requer o conhecimento prévio das posições dos dígitos e lida com números de versão com 2, 3 ou 4 componentes (como: a-1.2, foo-5.6.7, bar_baz_9.10.11.12 ). Ele também usa sort -f para dobrar letras maiúsculas e minúsculas juntas e manipula corretamente os diretórios misturados com arquivos:

ls -d | sort -f -t . -k 1,1 -k 2,2n -k 3,3n -k 4,4n

Note que esta versão limita o primeiro componente a um único dígito.

Se o seu sistema operacional de destino suporta ls -v , essa é claramente a solução superior.

    
por 20.05.2013 / 21:46
1

Solução de Perl:

ls log*.gz | perl -ne 'sub getnum{ $_[0] =~ /log(\d+)\.gz/; $1 }; push @A, $_; END{ print sort { getnum $a <=> $b } @A}'
    
por 09.03.2012 / 04:26
1
$ ls
log101.gz  log102.gz  log103.gz  log104.gz  log105.gz  log106.gz  log10.gz  log1.gz
$ ls | sort -t . -n -k1.4
log1.gz
log10.gz
log101.gz
log102.gz
log103.gz
log104.gz
log105.gz
log106.gz
    
por 23.03.2015 / 06:24