Como posso classificar uma lista com o nível major.minor.patch e às vezes rc corretamente?

18

Preciso classificar a lista a seguir com um script de shell e fazer com que a versão mais recente apareça na parte inferior ou superior. Como eu faria isso apenas com ferramentas de shell?

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
fonte
11
Veja também printf '%s\n' ${(on)array}em zsh. (quando a lista estiver na $arraymatriz).
Stéphane Chazelas

Respostas:

20

A classificação GNU tem -Vque pode lidar principalmente com uma lista como essa ( detalhes ):

 -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

No entanto, essas .rc*versões podem ser um pouco problemáticas, pois provavelmente devem ser classificadas antes da versão não-rc correspondente, se houver as duas, ou seja. Alguns sistemas de controle de versão (como o Debian) usam sufixos começando com um til ( ~) para marcar os pré-lançamentos e são classificados antes da versão sem sufixo, que são classificados antes das versões com outros sufixos. Aparentemente, isso é suportado pelo menos sortno meu sistema, como mostrado acima ( sort (GNU coreutils) 8.23).

ilkkachu
fonte
3
Me sniped por um par de segundos :)
rosuav
11
Muito obrigado. Nem imaginava que esse tipo teria uma opção como essa.
precisa
FWIW, -Vtambém suportado por padrão sortno OpenBSD, mas não no NetBSD.
Kusalananda
Aparentemente , o FreeBSD também parece que a página de manual também tem um exemplo de ordem de saída e parece idêntica à do OpenBSD.
22917 ilkkachu
7

Confira sort -V:

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

Os números de versão são bestas complicadas, com muito poucos padrões que regem as partes alfabéticas, mas tente isso com seus dados reais e verifique se são suficientes.

rosuav
fonte
Uau, ótimo! Isso funciona mesmo para um problema antigo meu com nomes de arquivos mayorNumber–minorNumer some text, onde a classificação do campo falha devido ao delimitador unicode. Obrigado pela dica!
Philippos
3

Isso pode ser feito como uma linha, mas dividida em várias linhas (nos tubos) aqui para facilitar a leitura, e também lida com os rc.

Se você não tem uma -Vopção para sua classificação, ou mesmo se tiver, precisará lidar com as ocasionais 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-/"

As primeiras sedtiras os caracteres não-numéricos
Os sortusa um .delimitador ( -t.), classificação numérica (- n), e as teclas ( -k)
As finais sedcoloca os caracteres não numéricos de volta no lugar.

MikeD
fonte
0

Obrigado por toda a inspiração - posso propor minha própria resposta: O programa de classificação pode ser levado a fazer o que é necessário. No final, trata-se de adicionar um quarto número ao controle de versão de três dígitos, classificá-lo e removê-lo novamente. Funciona - solução mais simples até agora, IMHO.

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

resultado:

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

....
Mandragor
fonte
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
fonte
release-5.0.0 deve aparecer APÓS .rc1 e .rc2 na lista. esse é o desafio aqui.
precisa