Compare números de versión de varios dígitos en bash

4

Al intentar escribir una secuencia de comandos que busca la versión de la aplicación, devuelve el valor. Mi problema es que el valor es de tres a cuatro intergers largos (ejemplo 4.3.2).

He buscado por un tiempo y no puedo encontrar ninguna sintaxis que te permita usar a! = o -ge para cualquier cosa mayor que un número con puntos. Solo me pregunto si alguien tiene una forma mejor o simplemente seguiré agregando para cada versión de lanzamiento.

Lo que quiero

else if [ $version1 -ge "9.0.8" ]; then

Cómo está escrito ahora

vercheck='mdls -name kMDItemVersion /Applications/iMovie.app'
version='echo ${vercheck:17}'
version1='echo ${version:1:5}'

[...]

else if [ $version1 = "9.0.8" ]; [ $version1 = "9.1.1" ]; then
    echo "You already have this version or a higher version installed"
    exit 0
    
pregunta balooga1 01.03.2013 - 17:52

5 respuestas

1

Creo que lo adapté ligeramente de enlace . Me gusta porque es bastante compacto y legible.

Esto es opcional, pero deseable IMO:

if [ "$#" != "2" ]
then
    echo "$0 requires exactly two arguments."
    exit 2
fi

Aquí está la carne:

Siempre uso $1 para "la versión instalada localmente" y $2 para "la versión con la que estoy comparando", por lo que si me deja con $? = 1 necesito actualizar, de lo contrario estoy al tanto. -fecha (o incluso más adelante):

function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }

if [ $(version $1) -gt $(version $2) ]; then
    echo "$1 is newer than $2"
    exit 0
elif [ $(version $1) -lt $(version $2) ]; then
    echo "$1 is older than $2"
    exit 1
else
    echo "$1 is identical to $2"
    exit 0
fi

Si todo lo que te importaba era si $1 estaba actualizado (es decir, igual o mayor que $2 ), podrías hacerlo aún más simple:

if [ $(version $1) -ge $(version $2) ]; then
    echo "No Newer Version Available"
    exit 0
fi

Cualquier código a continuación que solo se ejecutará si hay una versión más nueva disponible. De lo contrario, el script saldrá limpiamente en ese punto.

p.s .: Hago esto en / bin / zsh no en / bin / bash pero creo que hace una diferencia en este caso.

    
respondido por el TJ Luoma 06.03.2014 - 21:36
0

En realidad, comparar números de versión es bastante sencillo (al menos siempre que sean estrictamente numéricos) ya que están estructurados jerárquicamente de izquierda a derecha. Una comparación secuencial en ese mismo orden dará un resultado claro.

La siguiente función bash devolverá 0 (verdadero) si dos números de versión no son iguales , 1 (falso) si lo son, siempre que las variables $version_1 y $version_2 contienen solo un número arbitrario de grupos de dígitos separados por puntos:

function versions_not_equal {
    while [[ $version_1 != "0" || $version_2 != "0" ]]; do
        (( ${version_1%%.*} != ${version_2%%.*} )) && return 0
        [[ ${version_1} =~ "." ]] && version_1="${version_1#*.}" || version_1=0
        [[ ${version_2} =~ "." ]] && version_2="${version_2#*.}" || version_2=0
    done
    false
}

Implementar otras comparaciones, como mayor o igual , es tan simple como cambiar el operador de comparación de la evaluación aritmética (es decir, (( ${version_1%%.*} >= "${version_2%%.*}" )) ).

    
respondido por el kopischke 22.03.2013 - 00:35
0

Le puedo dar un ejemplo largo de "si la versión verificada está entre mín. y máx." y puede optimizarla para sus necesidades cambiando la cabeza -1 / cola -1 y cortando 1 variable:

min_ver="a-1.1.1"
max_ver="a-9.1.1"
check_ver="a-2.2.9"
if [ "$( echo -e "${min_ver}\n${max_ver}\n${check_ver}" | sort --sort=version | head -2 | tail -1)" == ${check_ver} ]
then
  echo YES - apply  ${check_ver}
fi
    
respondido por el Svetozar Urumov 06.03.2014 - 21:08
0

Aquí hay otra solución que:

  • no ejecuta ningún comando externo aparte de tr
  • no tiene restricción en el número de partes en la cadena de versión
  • puede comparar cadenas de versión con un número diferente de partes

Tenga en cuenta que es un código Bash que usa variables de matriz.

compare_versions()
{
    local v1=( $(echo "$1" | tr '.' ' ') )
    local v2=( $(echo "$2" | tr '.' ' ') )
    local len="$(max "${#v1[*]}" "${#v2[*]}")"
    for ((i=0; i<len; i++))
    do
        [ "${v1[i]:-0}" -gt "${v2[i]:-0}" ] && return 1
        [ "${v1[i]:-0}" -lt "${v2[i]:-0}" ] && return 2
    done
    return 0
}

La función devuelve:

  • 0 si las versiones son iguales (por cierto: 1.2 == 1.2.0)
  • 1 si la primera versión es más grande / más nueva
  • 2 si la segunda versión es más grande / más nueva

Sin embargo, # 1: requiere una función adicional (pero la función min es bastante útil de todas formas):

min()
{
    local m="$1"
    for n in "$@"
    do
        [ "$n" -lt "$m" ] && m="$n"
    done
    echo "$m"
}
Sin embargo, # 2: no puede comparar cadenas de versión con partes alfanuméricas (aunque en realidad no sería difícil agregarlas).

    
respondido por el mato 21.11.2016 - 19:34
0

Puede usar versión para verificar las restricciones de la versión

$ version ">=1.0, <2.0" "1.7"
$ go version | version ">=1.9"

Ejemplo de script Bash:

#!/bin/bash

if 'version -b ">=9.0.0" "$(gcc --version)"'; then
  echo "gcc version satisfies constraints >=9.0.0"
else
  echo "gcc version doesn't satisfies constraints >=9.0.0"
fi
    
respondido por el Ivan Dyachenko 25.02.2018 - 15:13

Lea otras preguntas en las etiquetas