Liste des fichiers triés numériquement

123

J'ai un tas de fichiers de log1à log164.

J'essaie de LISTER le répertoire (trié) dans un terminal UNIX mais les fonctions de tri fournissent uniquement le format suivant:

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

Ce que je veux c'est

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

Des suggestions dans ce que je pourrais utiliser pour faire ceci?

Volker Siegel
la source
8
Ceci est absolument une question de programmation, et ne mérite pas d'être migré simplement parce que la réponse implique le langage de programmation shell médiocre !!!
tchrist
Si vous savez à l' avance qu'ils sont nommés log1.gzpar log164.gz, alors qu'est-ce que vous devez même ls -1les pour?
Ruakh
1
@ruakh ls -1 affiche les résultats dans une colonne plutôt que dans l'ensemble
3
@Rabiani: Je sais ce qui se ls -1passe: il répertorie les noms de fichiers. Puisque vous connaissiez déjà les noms de fichiers, je ne comprenais pas pourquoi vous en aviez besoin. Mais puisque tu as accepté la réponse de Kevin, je le sais maintenant: tu n'en avais pas besoin. Ce qui a plus de sens. :-)
ruakh

Réponses:

40

bashLes accolades {},, les énumèrent dans l'ordre:

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

Pourquoi ne pas utiliser la lsfonction intégrée pour ce cas particulier, à savoir

-v natural sort of (version) numbers within text

Par exemple ls -1v log*

lik
la source
Solution géniale, bien que je souhaite une solution tout aussi simple sort: au cas où l’on aurait un tableau de chaînes plutôt qu’un répertoire de fichiers
Hubro
23
BSD / OS X cette option est autre chose: -v - Force unedited printing of non-graphic characters.
Kenorb
Malheureusement, l'option -v n'est pas disponible sur AIX (6.1)
bouvierr
6
Cela devrait être la meilleure réponse.
32r34wgf3e
1
pour MacOS cela fonctionnera, impossible de trouver une option comme mentionné, seulementls | sort -n
Ricky Levi
47

Avec GNU ls (c'est-à-dire sur Linux, Cygwin ou d'autres systèmes sur lesquels GNU ls est spécialement installé):

ls -v

En zsh:

echo *(n)

Dans d'autres coquilles:

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

Remplacez echopar printf '%s\n'si vous voulez que chaque nom de fichier soit sur une ligne séparée.

Si vous voulez aussi des métadonnées de fichier ( ls -l) et que vous n'avez pas GNU ls, vous devrez appeler lsséparément pour chaque nom de fichier ou groupe de noms de fichiers que vous souhaitez voir dans l'ordre lexicographique.

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

Pour éviter ces difficultés, utilisez suffisamment de zéros dans les noms de fichiers pour que le tri lexicographique soit adapté aux besoins de l’homme ( log001.gz, etc.).

Gilles
la source
29

Bien que la solution ls -1vsoit certainement la plus intéressante dans ce cas particulier, je pense qu’il est bon d’avoir également une solution qui fonctionne sortcomme dans la question initiale, car cela fonctionne également lorsque votre contribution ne vient pas ls. Dans ce cas, vous pouvez utiliser:

ls -1 | sort -n -k1.4

L' -noption indique au tri d'effectuer un tri numérique et -k 1.4définit la clé de tri sur le premier champ (le nom de fichier complet dans ce cas) à partir du 4ème caractère jusqu'au dernier.

Elmar Zander
la source
Dans mon cas, ls -1 | sort -n -k1.4ça ne marche pas. Il donne d'abord les caractères non triés jusqu'à 4 caractères, puis ceux triés après le 4e caractère. J'ai utilisé à la ls -1 |sort | sort -n -k1.4place et cela a fonctionné parfaitement.
Prabhu
3
@ Prabhu, au lieu de cela, vous pourriez le faire sort -k1.1,1.3 -k1.4n. sortLes mises en œuvre ne doivent pas nécessairement être stables , votre approche ne fonctionnera donc pas avec toutes les mises en œuvre. Voir aussi l' -Voption de GNU et FreeBSD sort.
Stéphane Chazelas
21

GNU sort(tel que disponible sous Linux) dispose d’un mode de "tri par version" qui interprète les nombres à l’intérieur de non-nombres comme vous le souhaitez:

De man 1 sort:

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

(Création de fichiers de test vides à la liste:
touch log1.gz log2.gz log3.gz log99.gz log100.gz log101.gz log102.gz)

Votre exemple de cas, en ajoutant l' -Voption (ou --version-sort):

ls -1 log*.gz | sort -V
log1.gz
log2.gz
log3.gz
log99.gz
log100.gz
log101.gz
log102.gz
Volker Siegel
la source
6

Si vous utilisez Mac ou BSD, essayez ceci:

ls -1 *.jpg | sort -n
Salvador Almaraz
la source
3

Ma version de Solaris ne prend pas en charge ls -v(grrr). Et la solution de tri fournie ci-dessus 1) requiert la connaissance de la position des chiffres dans le nom du fichier, et 2) ne gère pas des éléments tels que les numéros de version en plusieurs parties.

L’approche ci-dessous est compatible avec Solaris, ne nécessite aucune connaissance préalable des positions des chiffres et gère les numéros de version avec 2, 3 ou 4 composants (comme: a-1.2, foo-5.6.7, bar_baz_9.10.11.12). Il permet également sort -fde plier les majuscules et les minuscules et gère correctement les répertoires mélangés à des fichiers:

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

Notez que cette version limite le premier composant à un seul chiffre.

Si votre système d'exploitation cible prend en charge ls -vcette solution, il s'agit clairement de la meilleure.

MykennaC
la source
1

Solution Perl:

ls log*.gz | perl -ne 'sub getnum{ $_[0] =~ /log(\d+)\.gz/; $1 }; push @A, $_; END{ print sort { getnum $a <=> $b } @A}'
Barton Chittenden
la source
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
Kjohri
la source
1
Le -t .est superflu ici.
Stéphane Chazelas
0

Cela a fonctionné pour moi.

J'ai des fichiers 1.jpg 2.jpg ... 18.jpg

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

sortdevient confus avec la lssortie en raison de caractères de couleur non imprimables. Si vous essayez ceci:

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

cela fonctionnera parfaitement.

sortpeut ignorer les caractères non imprimables avec l' -ioption mais cela ne fonctionne toujours pas et je ne sais pas pourquoi.

Mais vous pouvez toujours décaper la couleur comme ça et ça sortmarchera:

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

J'espère qu'un jour sortaura une option pour cela.

cy8g3n
la source