Bash: converte uma string (número de versão) em um inteiro

3

Eu quero pegar a versão do glibc e usá-la em uma declaração if dizendo se o glibc é menor que 2.15 então.

No entanto, o problema é que, ao usar o ldd --version, isso é exibido como uma string. Eu preciso convertê-lo em um inteiro para fazer o menor que a comparação.

Anteriormente eu fiz dessa maneira

if [ "$(ldd --version | sed -n '1 p' | tr -cd '[:digit:]' | tail -c 3)" -lt 215 ]; then

Isso não é realmente muito bom, pois tenho que remover o ponto decimal e não posso fornecer uma comparação de número de versão verdadeira. A outra questão é que algumas versões da glibc têm vários pontos decimais (vistos aqui link ) o que significaria a minha comparação existente estragaria tudo.

Então, para esse fim, eu precisaria ser capaz de converter a versão glibc intacta em um inteiro e comparar corretamente os números de versão, mesmo com vários pontos decimais.

Alguma ideia? Obrigado

    
por dgibbs 12.03.2016 / 00:12

3 respostas

2

ldd --version | sed 's/.* //;q' | awk -F. '{ if ($1 > 2 || ($1 == 2 && $2 >= 15)) { exit 0 } else {exit 1} }'

Explicação:

O comando sed obtém a primeira linha de saída de ldd --version , retira tudo até e inclui o último espaço e, em seguida, sai (portanto, imprime apenas o número).

O sinal -F para awk define . como o separador de campo.

Se o primeiro número (antes do ponto) for maior que 2, ou se o primeiro número for 2 e o segundo número for pelo menos 15, o status de saída awk será "true ". Caso contrário, será falso.

Você pode usar isso em um script bash da seguinte forma:

if ldd --version | sed 's/.* //;q' | awk -F. '{ if ($1 > 2 || ($1 == 2 && $2 >= 15)) { exit 0 } else {exit 1} }' ; then
  echo "Version is 2.15 or later"
else
  echo "Version is too old."
fi
    
por 12.03.2016 / 00:27
1

Não converta a string da versão para um inteiro. Compare as cordas.

Isso é um pouco exagerado para o seu caso de uso, mas aqui está uma função do shell que compara cadeias de caracteres típicas da versão. Ele segue um subconjunto das regras de comparação da versão do Debian :

  • As versões são comparadas por partes. Cada pedaço consiste em uma sequência máxima de caracteres que consiste inteiramente de dígitos ou não contém dígitos.
  • As sequências não digitadas são comparadas na ordem lexicográfica.
  • As sequências de dígitos são comparadas de acordo com o valor decimal. Em particular, os zeros à esquerda são irrelevantes.

Observe que o último ponto: 1.01 é considerado igual a 1.1 . Este é o preço a pagar por 1.1 e 1.9 a ser considerado menor que 1.10 .

Este código requer dash, bash, ksh ou zsh. Para usá-lo com outros shells, como o BusyBox sh, substitua as chamadas por [ "STRING1" \> "STRING2" ] por expr "aSTRING1" \> "aSTRING2" .

version_ge () (
  version1="$1" version2="$2"
  while true; do
    prefix1="${version1%%[0-9]*}" prefix2="${version2%%[0-9]*}"
    if [ "$prefix1" \> "$prefix2" ]; then return 0; fi
    if [ "$prefix2" \> "$prefix1" ]; then return 1; fi
    version1="${version1#"$prefix1"}" version2="${version2#"$prefix2"}"
    prefix1="${version1%%[!0-9]*}" prefix2="${version2%%[!0-9]*}"
    version1="${version1#"$prefix1"}" version2="${version2#"$prefix2"}"
    case "$prefix2" in
      0*[!0]*) prefix2="${prefix2##"${prefix2%%[!0]*}"}";;
      *[!0]*) :;;
      *) return 0;;
    esac
    case "$prefix1" in
      0*[!0]*) prefix1="${prefix1##"${prefix1%%[!0]*}"}";;
      *[!0]*) :;;
      *) return 1;;
    esac
    if [ "${#prefix1}" -gt "${#prefix2}" ]; then return 0; fi
    if [ "${#prefix1}" -lt "${#prefix2}" ]; then return 1; fi
    if [ "$prefix1" \> "$prefix2" ]; then return 0; fi
    if [ "$prefix2" \> "$prefix1" ]; then return 1; fi
  done
)
    
por 12.03.2016 / 02:06
1

sort pode classificar números de versão; tirando proveito disso você poderia escrever algo assim:

if [ $(printf '%s\n2.15\n' $(ldd --version | sed -n '1s/.* //p') | sort -V | head -n 1) != 2.15 ]; then
    # ...
fi

printf '%s\n2.15\n' $(ldd --version | sed -n '1s/.* //p') imprime o número da versão ldd e 2.15 em duas linhas separadas, sort -V classifica-os em ordem crescente e head -n 1 imprime a primeira linha; a substituição do comando externo é substituída pela saída e a saída é comparada a 2.15 ; se a saída não for 2.15 , o if body será executado.

Exemplo de saída na minha máquina com ldd 2.21 :

% [ $(printf '%s\n2.15\n' $(ldd --version | sed -n '1s/.* //p') | sort -V | head -n 1) != 2.15 ] && printf 'Version %s is lower than 2.15\n' $(ldd --version | sed -n '1s/.* //p') || printf 'Version %s is equal or higher than 2.15\n' $(ldd --version | sed -n '1s/.* //p')
Version 2.21 is equal or higher than 2.15

Exemplo de saída em alguns valores codificados, apenas para demonstrar o método lida com a complexidade da classificação de versões:

% glibc_version=2.15
% [ $(printf '%s\n2.15\n' $glibc_version | sort -V | head -n 1) != 2.15 ] && printf 'Version %s is lower than 2.15\n' $glibc_version || printf 'Version %s is equal or higher than 2.15\n' $glibc_version
Version 2.15 is equal or higher than 2.15
% glibc_version=2.16  
% [ $(printf '%s\n2.15\n' $glibc_version | sort -V | head -n 1) != 2.15 ] && printf 'Version %s is lower than 2.15\n' $glibc_version || printf 'Version %s is equal or higher than 2.15\n' $glibc_version
Version 2.16 is equal or higher than 2.15
% glibc_version=2.15.1
[ $(printf '%s\n2.15\n' $glibc_version | sort -V | head -n 1) != 2.15 ] && printf 'Version %s is lower than 2.15\n' $glibc_version || printf 'Version %s is equal or higher than 2.15\n' $glibc_version
Version 2.15.1 is equal or higher than 2.15
% glibc_version=2.14
% [ $(printf '%s\n2.15\n' $glibc_version | sort -V | head -n 1) != 2.15 ] && printf 'Version %s is lower than 2.15\n' $glibc_version || printf 'Version %s is equal or higher than 2.15\n' $glibc_version
Version 2.14 is lower than 2.15
    
por 12.03.2016 / 02:40