Comment puis-je trier une liste avec le niveau major.minor.patch et parfois rc correctement?

18

Je dois trier la liste suivante avec un script shell et faire apparaître la dernière version en bas ou en haut. Comment pourrais-je faire cela avec des outils shell uniquement?

release-5.0.0.rc1
release-5.0.0.rc2
release-5.0.0
release-5.0.1
release-5.0.10
release-5.0.11
release-5.0.13
release-5.0.14
release-5.0.15
release-5.0.16
release-5.0.17
release-5.0.18
release-5.0.19
release-5.0.2
release-5.0.20
release-5.0.21
release-5.0.22
release-5.0.23
release-5.0.24
release-5.0.25
release-5.0.26
release-5.0.27
release-5.0.28
release-5.0.29
release-5.0.3
Mandragor
la source
1
Voir aussi printf '%s\n' ${(on)array}dans zsh. (lorsque la liste est dans le $arraytableau).
Stéphane Chazelas

Réponses:

20

Le tri GNU -Vpeut traiter principalement une liste comme celle-ci ( détails ):

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

$ cat vers
release-5.0.19
release-5.0.19~pre1
release-5.0.19-bigbugfix
release-5.0.2
release-5.0.20
$ sort -V vers
release-5.0.2
release-5.0.19~pre1
release-5.0.19
release-5.0.19-bigbugfix
release-5.0.20

Cependant, ces .rc*versions pourraient être un peu problématiques, car elles devraient probablement être triées avant la version non rc correspondante, s'il y avait les deux, c'est-à-dire. Certains systèmes de version (comme Debian) utilisent des suffixes commençant par un tilde ( ~) pour marquer les pré-versions, et ils trient avant la version sans suffixe, qui trie avant les versions avec d'autres suffixes. Apparemment, cela est pris en charge par au moins le sortsur mon système, comme indiqué ci-dessus ( sort (GNU coreutils) 8.23).

ilkkachu
la source
3
M'a coupé quelques secondes :)
rosuav
1
Merci beaucoup. N'imaginait même pas que ce genre aurait une option comme ça.
Mandragor
FWIW, -Végalement pris en charge par défaut sortsur OpenBSD, mais pas sur NetBSD.
Kusalananda
FreeBSD aussi, apparemment , la page de manuel contient également un exemple d'ordre de sortie, et semble identique à celle d'OpenBSD.
ilkkachu
7

Découvrez sort -V:

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

Les numéros de version sont des bêtes compliquées, avec très peu de normes régissant les parties alphabétiques, mais essayez cela sur vos données réelles et voyez si c'est suffisant.

rosuav
la source
Wow, super! Cela fonctionne même pour un ancien problème avec les noms de fichiers mayorNumber–minorNumer some text, où le tri des champs échoue à cause du délimiteur unicode. Merci pour l'astuce!
Philippos
3

Cela peut être fait en une seule ligne, mais divisé en plusieurs lignes (au niveau des tuyaux) ici pour plus de lisibilité, et gère rcégalement les.

Si vous n'avez pas d' -Voption pour votre tri, ou même si vous en avez, vous devrez vous occuper des occasionnels rc:

cat versionlist |
sed -e "s/release-//" -e "s/rc//" |
sort -t. -n -k1,1 -k2,2 -k3,3 -k4,4 |
sed -r -e "s/([^.]+)\.([^.]+)\.([^.]+)\.([^.]+)/\1.\2.\3.rc\4/" -e "s/^/release-/"

La première sedsupprime les caractères non numériques.
La sortutilise un .délimiteur ( -t.), un tri numérique (- n) et des touches ( -k).
La finale sedremet les caractères non numériques en place.

MikeD
la source
0

Merci pour toute l'inspiration - Puis-je proposer ma propre réponse: le programme de tri peut être amené à faire ce qui est nécessaire. En fin de compte, il s'agit d'ajouter un quatrième numéro au versioning à 3 chiffres, de le trier, puis de le supprimer à nouveau. Fonctionne - la solution la plus simple à ce jour, à mon humble avis.

cat versionlist |\
sed -r "s/([0-9]+\.[0-9]+\.[0-9]+$)/\1\.99999/"|sort -V|sed s/\.99999$//

résultat:

release-5.0.0.rc1
release-5.0.0.rc2
release-5.0.0

....
Mandragor
la source
0
$ cat /tmp/tmp.tmp
release-5.0.0.rc1
release-5.0.0.rc2
release-5.0.0
release-5.0.1
release-5.0.10
release-5.0.11
release-5.0.13
release-5.0.14
release-5.0.15
release-5.0.16
release-5.0.17
release-5.0.18
release-5.0.19
release-5.0.2
release-5.0.20
release-5.0.21
release-5.0.22
release-5.0.23
release-5.0.24
release-5.0.25
release-5.0.26
release-5.0.27
release-5.0.28
release-5.0.29
release-5.0.3

$ cat /tmp/tmp.tmp | awk -F\- '{ print $2,$1 }' | sort -n | awk '{ print $2 "-" $1 }'
release-5.0.0
release-5.0.0.rc1
release-5.0.0.rc2
release-5.0.1
release-5.0.10
release-5.0.11
release-5.0.13
release-5.0.14
release-5.0.15
release-5.0.16
release-5.0.17
release-5.0.18
release-5.0.19
release-5.0.2
release-5.0.20
release-5.0.21
release-5.0.22
release-5.0.23
release-5.0.24
release-5.0.25
release-5.0.26
release-5.0.27
release-5.0.28
release-5.0.29
release-5.0.3

$
boardrider
la source
la version 5.0.0 devrait venir APRÈS .rc1 et .rc2 dans la liste. c'est le défi ici.
Mandragor