bash
, irão enumerá-las na ordem:
for file in log{1..164}.gz; do
process "$file"
done
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 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*
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).
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.
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
se você usa Mac ou BSD, tente isto:
ls -1 *.jpg | sort -n
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.
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}'
$ 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