¿Cómo comparar la versión de un programa en un script de shell?


14

Supongamos que quiero comparar la gccversión para ver si el sistema tiene instalada la versión mínima o no.

Para verificar la gccversión, ejecuté lo siguiente

gcc --version | head -n1 | cut -d" " -f4

La salida fue

4.8.5

Entonces, escribí una ifdeclaración simple para comparar esta versión con algún otro valor

if [ "$(gcc --version | head -n1 | cut -d" " -f4)" -lt 5.0.0 ]; then
    echo "Less than 5.0.0"
else
    echo "Greater than 5.0.0"
fi

Pero arroja un error:

[: integer expression expected: 4.8.5

Comprendí mi error de que estaba usando cadenas para comparar y el -ltentero requerido. Entonces, ¿hay alguna otra forma de comparar las versiones?


@ 123 No pasa nada
— Abhimanyu Saharan

1
También hay una pregunta de desbordamiento de pila con un montón de sugerencias diferentes para comparar cadenas de versiones.
— n

1
Mucho más simple que usar tuberías:gcc -dumpversion
— Victor Lamoine

Respuestas:


21

No sé si es hermoso, pero está funcionando para todos los formatos de versión que conozco.

#!/bin/bash
currentver="$(gcc -dumpversion)"
requiredver="5.0.0"
 if [ "$(printf '%s\n' "$requiredver" "$currentver" | sort -V | head -n1)" = "$requiredver" ]; then 
        echo "Greater than or equal to 5.0.0"
 else
        echo "Less than 5.0.0"
 fi

( Nota: mejor versión del usuario 'comodín': https://unix.stackexchange.com/users/135943/wildcard , condición adicional eliminada)


3
Al principio pensé que esto era horrible, y luego me di cuenta de que la belleza de las secuencias de comandos de shell es precisamente abusar de herramientas como esta. +1
— Boicot SE para Monica Cellio

2
Esto se rompe si hay signos '%' en la declaración de impresión. Mejor reemplazar printf "$requiredver\n$currentver"con printf '%s\n' "$requiredver" "$currentver".
— phk

1
-Ves una extensión de GNU, por lo sort(1)tanto, esta solución no es portátil.
— stefanct

1
sort -nfunciona casi de la misma manera en el caso de las versiones numéricas.
— Rockallite

1
@LucianoAndressMartini, mira lo que piensas de mi edición.
— Comodín el

2

Aquí doy una solución para comparar las versiones de Unix Kernel. Y debería funcionar para otros, como gcc. Solo me importa el primer número de versión 2, pero puede agregar otra capa de lógica. Es un trazador de líneas y lo escribí en varias líneas para su comprensión.

check_linux_version() {
    version_good=$(uname -r | awk 'BEGIN{ FS="."}; 
    { if ($1 < 4) { print "N"; } 
      else if ($1 == 4) { 
          if ($2 < 4) { print "N"; } 
          else { print "Y"; } 
      } 
      else { print "Y"; }
    }')

    #if [ "$current" \< "$expected" ]; then
    if [ "$version_good" = "N" ]; then
        current=$(uname -r)
        echo current linux version too low
        echo current Linux: $current
        echo required 4.4 minimum
        return 1
    fi
}

Puede modificar esto y usarlo para verificar la versión de gcc.


¿+1 es compatible con otros similares a Unix? (Mi solución no es)
— Luciano Andress Martini

1

Solíamos comprobar muchas versiones en un archivo MAKU de GNU. Destrozamos a través de las instalaciones de archivo. Tuvimos que detectar viejos Binutils y compiladores con errores y solucionarlos sobre la marcha.

El patrón que utilizamos fue:

#!/usr/bin/env bash

CC=$(command -v gcc)
GREP=$(command -v grep)

# Fixup CC and GREP as needed. It may be needed on AIX, BSDs, and Solaris
if [[ -f "/usr/gnu/bin/grep" ]]; then
    GREP="/usr/gnu/bin/grep"
elif [[ -f "/usr/linux/bin/grep" ]]; then
    GREP="/usr/linux/bin/grep"
elif [[ -f "/usr/xpg4/bin/grep" ]]; then
    GREP="/usr/xpg4/bin/grep"
fi

# Check compiler for GCC 4.8 or later
GCC48_OR_LATER=$("$CXX" -v 2>&1 | "$GREP" -i -c -E "gcc version (4\.[8-9]|[5-9]\.)")
if [[ "$GCC48_OR_LATER" -ne 0 ]];
then
   ...
fi

# Check assembler for GAS 2.19 or later
GAS219_OR_LATER=$("$CXX" -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | "$GREP" -c -E "GNU assembler version (2\.19|2\.[2-9]|[3-9])")
if [[ "$GAS219_OR_LATER" -ne 0 ]];
then
   ...
fi

¡Agradable! ¡Esto funciona y es súper fácil de extender y muy portátil!
— Brad Parks,

1

Versión más corta:

version_greater_equal()
{
    printf '%s\n%s\n' "$2" "$1" | sort -V -C
}

version_greater_equal "${gcc_version}" 8.2 || die "need 8.2 or above"

(1) Esta es una variación menor de las respuestas ya dadas. Puede agregar valor agregando una explicación, que aún no se ha publicado. (2)  printf '%s\n'es lo suficientemente bueno; printfrepetirá la cadena de formato según sea necesario.
— G-Man dice 'reinstalar a Monica'

Normalmente prefiero editar las respuestas existentes, pero eliminar la mitad de ellas es complicado: otros pueden ver el valor donde yo no. Lo mismo para explicaciones detalladas. Menos es más.
— MarcH

Sé que printfrepite la cadena de formato, pero la sintaxis (¡falta!) Para esto es IMHO oscura; así que uso esto solo cuando es necesario = cuando el número de argumentos es grande o variable.
— MarcH

1
function version_compare () {
  function sub_ver () {
    local len=${#1}
    temp=${1%%"."*} && indexOf=`echo ${1%%"."*} | echo ${#temp}`
    echo -e "${1:0:indexOf}"
  }
  function cut_dot () {
    local offset=${#1}
    local length=${#2}
    echo -e "${2:((++offset)):length}"
  }
  if [ -z "$1" ] || [ -z "$2" ]; then
    echo "=" && exit 0
  fi
  local v1=`echo -e "${1}" | tr -d '[[:space:]]'`
  local v2=`echo -e "${2}" | tr -d '[[:space:]]'`
  local v1_sub=`sub_ver $v1`
  local v2_sub=`sub_ver $v2`
  if (( v1_sub > v2_sub )); then
    echo ">"
  elif (( v1_sub < v2_sub )); then
    echo "<"
  else
    version_compare `cut_dot $v1_sub $v1` `cut_dot $v2_sub $v2`
  fi
}

### Usage:

version_compare "1.2.3" "1.2.4"
# Output: <

El crédito va a @Shellman

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.