Come confrontare la versione di un programma in uno script di shell?


14

Supponiamo che io voglia confrontare la gccversione per vedere se il sistema ha la versione minima installata o meno.

Per verificare la gccversione, ho eseguito quanto segue

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

L'output è stato

4.8.5

Quindi, ho scritto una semplice ifdichiarazione per verificare questa versione con qualche altro valore

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

Ma genera un errore:

[: integer expression expected: 4.8.5

Ho capito il mio errore che stavo usando le stringhe per confrontare e -ltrichiede l'intero. Quindi, c'è un altro modo per confrontare le versioni?


@ 123 Non succede nulla
Abhimanyu Saharan,

1
C'è anche una domanda Stack Overflow con una serie di suggerimenti diversi per confrontare le stringhe di versione.
n.

1
Molto più semplice dell'uso delle pipe:gcc -dumpversion
Victor Lamoine,

Risposte:


21

Non so se sia bello, ma funziona con tutti i formati di versione che conosco.

#!/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: versione migliore dell'utente 'jolly': https://unix.stackexchange.com/users/135943/wildcard , rimossa condizione aggiuntiva)


3
All'inizio ho pensato che fosse orribile, e poi ho capito che la bellezza dello scripting della shell sta proprio nel maltrattare strumenti come questo. +1
Boicottaggio SE per Monica Cellio,

2
Questo si interrompe se ci sono segni '%' nell'istruzione print. Meglio sostituirlo printf "$requiredver\n$currentver"con printf '%s\n' "$requiredver" "$currentver".
phk,

1
-Vè un'estensione GNU, sort(1)quindi questa soluzione non è portatile.
Stefanct,

1
sort -nfunziona più o meno allo stesso modo in caso di versioni numeriche.
Rockallite,

1
@LucianoAndressMartini, vedi cosa ne pensi della mia modifica.
Wildcard il

2

Qui do una soluzione per confrontare le versioni del kernel Unix. E dovrebbe funzionare per altri come gcc. Mi interessa solo il primo numero di versione 2 ma è possibile aggiungere un altro livello di logica. È una riga e l'ho scritto in più righe per la comprensione.

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
}

Puoi modificarlo e usarlo per il controllo della versione di gcc.


+1 è compatibile con altri simili a Unix? (La mia soluzione non è)
Luciano Andress Martini,

1

In passato eseguivamo molti controlli di versione in un makefile GNU. Abbiamo sborsato attraverso le strutture del makefile. Abbiamo dovuto rilevare vecchi Binutils e compilatori con buggy e risolverli al volo.

Il modello che abbiamo usato era:

#!/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

Bello! Funziona ed è super facile da estendere e molto portatile!
Brad Parks il

1

Versione più 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) Questa è una variante minore delle risposte già fornite. È possibile aggiungere valore aggiungendo una spiegazione, che non è stata ancora pubblicata. (2)  printf '%s\n'è abbastanza buono; printfripeterà la stringa di formato secondo necessità.
G-Man dice "Reinstate Monica" il

Normalmente preferisco modificare le risposte esistenti, ma eliminarne la metà è complicato: altri potrebbero vedere un valore dove io no. Lo stesso per spiegazioni dettagliate. Meno è meglio.
Marc

So che printfripete la stringa di formato ma io la sintassi (la mancanza di!) Per questo è oscura di IMHO; quindi lo uso solo quando richiesto = quando il numero di argomenti è grande o variabile.
Marc

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: <

Il merito va a @Shellman

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.