Jak mogę posortować listę z poziomem major.minor.patch, a czasem rc poprawnie?

18

Muszę posortować poniższą listę za pomocą skryptu powłoki i sprawić, aby najnowsza wersja pojawiła się na dole lub na górze. Jak miałbym to zrobić tylko za pomocą narzędzi powłoki?

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
źródło
1
Zobacz też printf '%s\n' ${(on)array} w zsh. (gdy lista znajduje się w $arraytablicy).
Stéphane Chazelas,

Odpowiedzi:

20

GNU sort ma, -Vże może poradzić sobie z taką listą ( szczegóły ):

 -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

Te .rc*wersje mogą jednak stanowić pewien problem, ponieważ prawdopodobnie powinny zostać posortowane przed odpowiednią wersją inną niż rc, jeśli tak się dzieje, to znaczy, że są obie. Niektóre systemy wersjonowania (takie jak Debian) używają sufiksów rozpoczynających się ~od znaku tyldy ( ) do oznaczania wersji wstępnych i sortują przed wersją bez sufiksu, który sortuje przed wersjami z innymi sufiksami. Najwyraźniej jest to obsługiwane przez co najmniej sortw moim systemie, jak pokazano powyżej ( sort (GNU coreutils) 8.23).

ilkkachu
źródło
3
Oderwał mnie od siebie kilka sekund :)
rosuav
1
Wielkie dzięki. Nawet nie wyobrażałem sobie, że taki rodzaj miałby taką opcję.
Mandragor
FWIW, -Vdomyślnie obsługiwany także sortw OpenBSD, ale nie w NetBSD.
Kusalananda
Najwyraźniej również strona FreeBSD ma tam przykładową kolejność wyjściową i wygląda identycznie jak w OpenBSD.
ilkkachu
7

Sprawdź sort -V:

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

Numery wersji to skomplikowane bestie, z bardzo nielicznymi standardami rządzącymi częściami alfabetycznymi, ale wypróbuj to na swoich rzeczywistych danych i sprawdź, czy to wystarczy.

rosuav
źródło
Wow świetne! Działa to nawet w przypadku mojego starego problemu z nazwami plików mayorNumber–minorNumer some text, gdzie sortowanie pól kończy się niepowodzeniem z powodu ogranicznika Unicode. Dziękuję za podpowiedź!
Philippos
3

Można to zrobić jako jedną linię, ale tutaj podzielono na wiele linii (na potokach), aby zapewnić czytelność i obsługuje rc 's'.

Jeśli nie masz takiej -Vopcji, a nawet jeśli tak, będziesz musiał poradzić sobie z okazjonalnymi 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-/"

Pierwszy sedusuwa znaki nienumeryczne
. sortUżywa .ogranicznika ( -t.), sortowania numerycznego (- n) i klawiszy ( -k)
. Ostatni sedumieszcza znaki nienumeryczne z powrotem na swoim miejscu.

MikeD
źródło
0

Dzięki za całą inspirację - mogę zaproponować własną odpowiedź: program sortowania można oszukać, aby zrobić to, co jest potrzebne. Na koniec chodzi o dodanie czwartej liczby do 3-cyfrowej wersji, posortowanie, a następnie usunięcie go ponownie. Działa - jak dotąd najprostsze rozwiązanie, IMHO.

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

wynik:

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

....
Mandragor
źródło
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
źródło
Wersja 5.0.0 powinna pojawić się PO .rc1 i .rc2 na liście. to jest wyzwanie tutaj.
Mandragor,