Comment comparer la version d'un programme dans un script shell?

14

Supposons que je veuille comparer la gccversion pour voir si la version minimale du système est installée ou non.

Pour vérifier la gccversion, j'ai exécuté ce qui suit

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

La sortie était

4.8.5

J'ai donc écrit une simple ifdéclaration pour comparer cette version avec une autre valeur

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

Mais cela jette une erreur:

[: integer expression expected: 4.8.5

J'ai compris mon erreur que j'utilisais des chaînes pour comparer et l' -ltentier requis. Alors, existe-t-il un autre moyen de comparer les versions?

Abhimanyu saharien
la source
@ 123 Rien ne se passe
Abhimanyu Saharan
1
Il y a aussi une question Stack Overflow avec un tas de suggestions différentes pour comparer les chaînes de version.
n.st
1
Beaucoup plus simple que d'utiliser des tuyaux:gcc -dumpversion
Victor Lamoine

Réponses:

21

Je ne sais pas si c'est beau, mais cela fonctionne pour tous les formats de version que je connais.

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

( Remarque: meilleure version par l'utilisateur 'wildcard': https://unix.stackexchange.com/users/135943/wildcard , condition supplémentaire supprimée)

Luciano Andress Martini
la source
3
Au début, je pensais que c'était horrible, puis j'ai réalisé que la beauté des scripts shell réside précisément dans l'utilisation abusive d'outils comme celui-ci. +1
Boycott SE pour Monica Cellio
2
Cela casse s'il y a des signes «%» dans l'instruction d'impression. Mieux vaut remplacer printf "$requiredver\n$currentver"par printf '%s\n' "$requiredver" "$currentver".
phk
1
-Vest une extension GNU sort(1)donc cette solution n'est pas portable.
Stefanct
1
sort -nfonctionne à peu près de la même manière dans le cas des versions numériques.
Rockallite
1
@LucianoAndressMartini, voyez ce que vous pensez de mon montage.
Wildcard
2

Ici, je donne une solution pour comparer les versions du noyau Unix. Et cela devrait fonctionner pour d'autres comme gcc. Je ne me soucie que des 2 premiers numéros de version, mais vous pouvez ajouter une autre couche de logique. C'est un liner et je l'ai écrit en plusieurs lignes pour comprendre.

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
}

Vous pouvez le modifier et l'utiliser pour vérifier la version de gcc.

Kemin Zhou
la source
+1 est-il compatible avec d'autres appareils de type Unix? (Ma solution n'est pas)
Luciano Andress Martini
1

Nous faisions beaucoup de vérification de version dans un makefile GNU. Nous avons bombardé les installations de makefile. Nous avons dû détecter les vieux Binutils et les compilateurs de buggy et les contourner à la volée.

Le modèle que nous avons utilisé était:

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

la source
Agréable! Cela fonctionne et est super facile à étendre et très portable!
Brad Parks
1

Version plus courte:

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"
Mars
la source
(1) Il s'agit d'une variante mineure des réponses déjà données. Vous pouvez ajouter de la valeur en ajoutant une explication, qui n'a pas encore été publiée. (2)  printf '%s\n'est assez bon; printfrépétera la chaîne de format selon les besoins.
G-Man dit `` Réintègre Monica '' le
Je préfère normalement éditer les réponses existantes mais en supprimer la moitié est délicat: d'autres peuvent voir la valeur là où je ne le vois pas. Idem pour les explications verbeuses. Moins est plus.
MarcH
Je sais que printfrépète la chaîne de format mais moi la syntaxe (manque de!) Pour cela est IMHO obscure; donc je l'utilise uniquement lorsque cela est nécessaire = lorsque le nombre d'arguments est grand ou 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: <

Le crédit va à @Shellman

Xaqron
la source