Listar arquivos classificados numericamente


123

Eu tenho um monte de arquivos de log1para log164.

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

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 sobre o que eu poderia usar para fazer isso?


8
Esta é absolutamente uma questão de programação e não merece ser migrada apenas porque a resposta envolve a linguagem de programação humilde !!!
tchrist

Se você sabe de antemão que eles estão nomeados log1.gzatravés log164.gz, então o que você precisa mesmo de ls -1-los para?
Ruakh 9/12

1
@ruakh ls -1 exibe os resultados em uma coluna em vez de em todo

3
@ Rabiani: Eu sei o que ls -1faz: lista nomes de arquivos. Como você já conhecia os nomes dos arquivos, não entendi para o que você precisava. Mas desde que você aceitou a resposta de Kevin, agora eu sei: você não precisava dela. O que faz mais sentido. :-)
ruakh

Respostas:


40

bash's chaves,, {}irá enumerá-los em ordem:

for file in log{1..164}.gz; do
    process "$file"
done

267

Por que não usar o lsrecurso interno para esse caso em particular,

-v natural sort of (version) numbers within text

Por exemplo ls -1v log*


Solução impressionante, embora eu gostaria que houvesse uma solução igualmente simples, utilizando sort, no caso de um tem uma matriz de strings em vez de um diretório de arquivos
Hubro

23
No BSD / OSX esta opção é outra coisa: -v - Force unedited printing of non-graphic characters.
kenorb

Infelizmente, a opção -v não está disponível no AIX (6.1)
bouvierr

6
Essa deve ser a melhor resposta.
32r34wgf3e

1
para MacOS isso vai funcionar, não poderia encontrar uma opção como mencionado, únicals | sort -n
Ricky Levi

47

Com o GNU ls (ou seja, no Linux, Cygwin ou outros sistemas que possuem o GNU ls especificamente instalado):

ls -v

No zsh:

echo *(n)

Em outras conchas:

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

Substitua echopor printf '%s\n'se desejar que cada nome de arquivo esteja em uma linha separada.

Se você também deseja metadados de arquivo ( ls -l) e não possui GNU ls, precisará chamar lsseparadamente cada nome de arquivo ou grupo de nomes de arquivo que deseja ver em ordem lexicográfica.

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

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


29

Embora a solução ls -1vseja certamente a melhor neste caso em particular, acho bom ter também uma que funcione sortcomo na pergunta original, pois isso funciona também quando a sua entrada não vem ls. Nesse caso, você pode usar:

ls -1 | sort -n -k1.4

A -nopção informa a classificação para classificar numericamente e -k 1.4define a chave de classificação para o primeiro campo (que é o nome do arquivo inteiro nesse caso), começando do 4º caractere até o último.


No meu caso, ls -1 | sort -n -k1.4não funciona. Dá os não ordenados no início até 4 caracteres, depois os ordenados após o 4º caractere. Eu usei em ls -1 |sort | sort -n -k1.4vez disso e funcionou perfeitamente.
Prabhu

3
@ Prabhu, em vez disso, você poderia fazer sort -k1.1,1.3 -k1.4n. sortas implementações não precisam ser estáveis, portanto sua abordagem não funcionará com todas as implementações. Veja também a -Vopção do GNU e FreeBSD sort.
Stéphane Chazelas

21

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

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 de caso, adicionando a -Vopção (ou --version-sort):

ls -1 log*.gz | sort -V
log1.gz
log2.gz
log3.gz
log99.gz
log100.gz
log101.gz
log102.gz


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 trata de coisas como números de versão com várias partes.

A abordagem abaixo é compatível com Solaris, não requer conhecimento prévio das posições dos dígitos e lida com os 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 -fpara dobrar maiúsculas e minúsculas e manipula adequadamente diretórios misturados com arquivos:

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

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

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


1

Solução Perl:

ls log*.gz | perl -ne 'sub getnum{ $_[0] =~ /log(\d+)\.gz/; $1 }; push @A, $_; END{ print sort { getnum $a <=> $b } @A}'

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

1
O -t .é supérfluo aqui.
Stéphane Chazelas

0

Isso funcionou para mim.

Eu tenho arquivos 1.jpg 2.jpg ... 18.jpg

$ echo *.jpg | tr -s ' ' '\n' | sort -n

sortestá ficando confuso com a lssaída devido a caracteres coloridos não imprimíveis. Se você tentar isso:

ls -1 --color=none *.jpg | sort -n

funcionará perfeitamente.

sortpode ignorar caracteres não imprimíveis com a -iopção, mas ainda não funciona e não sei por quê.

Mas você sempre pode tirar a cor dessa maneira e sortfuncionará:

ls -1 --color=always *.jpg | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" | sort -n

Espero que um dia sorttenha uma opção para isso.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.