¿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.