web-dev-qa-db-fra.com

Vérifier si la version de Bash est> = numéro de version donné

Je dois tester si le numéro de version de Bash est> = à un numéro spécifique. Par exemple j'ai:

$ bash --version
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Pour utiliser des tableaux associatifs, le numéro de version de bash doit être> = 4.

Dans mon script bash, je voudrais mettre en place un test à une ligne de la manière la plus élégante/efficace/lisible possible, mais d'autres approches sont également acceptées.

10
WinEunuuchs2Unix

Essayer:

$ [ "${BASH_VERSINFO:-0}" -ge 4 ] && echo "bash supports associative arrays"
bash supports associative arrays

BASH_VERSINFO est une variable de tableau en lecture seule dont les membres contiennent des informations de version pour cette instance de bash. Depuis qu'il a été introduit avec bash 2.0, il est probablement supporté par toutes les versions de bash que vous rencontrerez. Mais, par prudence, nous incluons une valeur par défaut de 0 pour toute version antérieure de bash pour laquelle cette variable est non définie.

Extraire les informations de version d'autres programmes

Vous avez posé des questions sur LibreOffice, Python, le noyau, etc.

LibreOffice produit des informations de version qui ressemblent à:

$ libreoffice --version
LibreOffice 5.2.6.2 20m0(Build:2)

Pour extraire le numéro de version:

$ libreoffice --version | cut -d' ' -f2
5.2.6.2

Pour le python:

$ python -c 'import platform; print(platform.python_version())'
2.7.13

Pour obtenir la version du noyau, utilisez uname:

$ uname -r
4.9.0-2-AMD64
13
John1024

Au lieu de comparer les numéros de version, vous pouvez tester directement la fonctionnalité elle-même. declare -A renvoie 2 (au moins dans Bash 3.2) s'il ne reconnaît pas -A, alors testez-le (il affiche également une erreur):

unset assoc
if ! declare -A assoc ; then
    echo "associative arrays not supported!"
    exit 1
fi

(declare -A var échoue également si var est un tableau non associatif, donc unset le premier.)

Bien que je ne présume pas que quiconque se tourne vers BSP en backport, il est généralement plus approprié de vérifier les fonctionnalités, pas les versions. Même dans le cas de Bash, quelqu'un pourrait compiler une version avec seulement des fonctionnalités limitées ...


Le cas plus général de test des numéros de version comprend deux parties: 1) comment trouver le bon numéro de version à tester et 2) comment le comparer à une autre valeur.

Le premier est le plus difficile. De nombreux programmes indiquent leur numéro de version avec un indicateur de ligne de commande tel que --version ou -v, mais le format de sortie varie et il peut être difficile de choisir le numéro de version par programme. Ensuite, il y a la possibilité d'avoir plusieurs versions du même programme installées en même temps.

La seconde dépend de la connaissance du format des numéros de version. dpkg peut comparer numéros de version de style Debian (que je pense inclut semver tapez les versions en tant que sous-ensemble):

if dpkg --compare-versions 4.3.30 ge 4.0.0 ; then
    echo "it's version 4.x"
fi

Ou, simplement pour combiner ce qui précède:

bashver=$( bash --version | sed -Ee 's/GNU bash, version ([0-9.]+).*/\1/;q' )
if dpkg --compare-versions "$bashver" ge 4.0.0 ; then
    echo "'bash' in your path is version 4.x"
fi
8
ilkkachu

Il y a plusieurs façons d'aborder ce que vous voulez réaliser.

1. Utilisez $ BASH_VERSION

Il suffit de voir ce que contient la variable $BASH_VERSION. Personnellement, j'utiliserais le sous-shell comme ceci:

$ (read -d "." version trash <<< $BASH_VERSION; echo "$version" )
4

Notez que la syntaxe <<< pour here-doc n'est pas portable, si vous allez l'utiliser avec /bin/sh, qui est Dash sur Ubuntu et qui pourrait être quelque chose d'autre sur un autre système.

Une autre manière est via l'instruction case ou if. Personnellement, je ferais ceci:

bash-4.3$ case $BASH_VERSION in 4.*) echo "Can use associative arrays";; ?) echo "can't use associative arrays" ;; esac
Can use associative arrays

Probablement pour des raisons de portabilité, vous devriez probablement vérifier si une telle variable est même définie du tout avec quelque chose comme [ -n $BASH_VERSION ]

Ceci peut être totalement réécrit en tant que fonction à utiliser dans un script. Quelque chose d'un long les lignes de:

#!/bin/bash
version_above_4(){
    # check if $BASH_VERSION is set at all
    [ -z $BASH_VERSION ] && return 1

    # If it's set, check the version
    case $BASH_VERSION in 
        4.*) return 0 ;;
        ?) return 1;; 
    esac
}

if version_above_4
then
    echo "Good"
else
    echo "No good"
fi

Ce n'est pas un one-liner, même si c'est beaucoup mieux. La qualité plutôt que la quantité.

2. Vérifiez ce qui est installé

Pour cela, vous devez filtrer la sortie de apt-cache policy comme si

$ apt-cache policy bash | awk -F '[:.]' '/Installed:/{printf "%s\n",substr($2,2)}'
4

dpkg-query peut également être utile avec un filtrage via awk.

$ dpkg-query -W bash | awk '{print substr($2,1,1)}'   
4

Notez que ce n'est pas portable, car s'il n'y a pas dpkg ou apt installé sur un système (par exemple, RHEL ou FreeBSD), cela ne vous servira à rien.

3. Utilisez set -e pour quitter le script en cas d'erreur

Une façon de le contourner consiste simplement à utiliser des tableaux associatifs et à quitter lorsque bash ne peut pas les utiliser. set -e la ligne ci-dessous #!/bin/bash permettra au script de se quitter s'il ne peut pas utiliser de tableau associatif.

Pour cela, vous devrez explicitement dire à l'utilisateur: "Hé, vous avez vraiment besoin de la version 4.3 ou ultérieure de bash, sinon le script ne fonctionnera pas". La responsabilité incombe ensuite à l'utilisateur, même si certains pourraient dire que ce n'est pas vraiment une bonne approche pour le développement de logiciels.

4. Abandonnez tout espoir et écrivez des scripts portables, compatibles avec POSIX

Les scripts bash ne sont pas portables car sa syntaxe n'est pas compatible avec Bourne Shell. Si le script que vous écrivez doit être utilisé sur différents systèmes, pas seulement Ubuntu, abandonnez tout espoir et recherchez des moyens d'utiliser autre chose que des tableaux associatifs. Cela peut inclure deux tableaux ou l’analyse d’un fichier de configuration. Pensez également à passer à un autre langage, Perl ou Python, où la syntaxe est au moins plus portable que bash.

5

Une ligne n'est pas possible mais un script bash est possible

J'ai développé un script qui s'appuie sur des réponses dans Stack Overflow. L'une de ces réponses a conduit un employé de Dell à écrire des comparaisons de numéros de version en 2004 pour l'application DKMS.

Le code

Le script bash ci-dessous doit être marqué comme exécutable à l'aide de la commande chmod a+x script-name. J'utilise le nom /usr/local/bin/testver:

#!/bin/bash

# NAME: testver
# PATH: /usr/local/bin
# DESC: Test a program's version number >= to passed version number
# DATE: May 21, 2017. Modified August 5, 2019.

# CALL: testver Program Version

# PARM: 1. Program - validated to be a command
#       2. Version - validated to be numberic

# NOTE: Extracting version number Perl one-liner found here:
#       http://stackoverflow.com/questions/16817646/extract-version-number-from-a-string

#       Comparing two version numbers code found here:
#       http://stackoverflow.com/questions/4023830/how-compare-two-strings-in-dot-separated-version-format-in-bash

# Map parameters to coder-friendly names.
Program="$1"
Version="$2"

# Program name must be a valid command.
command -v $Program >/dev/null 2>&1 || { echo "Command: $Program not found. Check spelling."; exit 99; }

# Passed version number must be valid format.
if ! [[ $Version =~ ^([0-9]+\.?)+$ ]]; then
    echo "Version number: $Version has invalid format. Aborting.";
    exit 99
fi

InstalledVersion=$( "$Program" --version | Perl -pe '($_)=/([0-9]+([.][0-9]+)+)/' )
# echo "Installed Version: $InstalledVersion"

if [[ $InstalledVersion =~ ^([0-9]+\.?)+$ ]]; then
    l=(${InstalledVersion//./ })
    r=(${Version//./ })
    s=${#l[@]}
    [[ ${#r[@]} -gt ${#l[@]} ]] && s=${#r[@]}

    for i in $(seq 0 $((s - 1))); do
        # echo "Installed ${l[$i]} -gt Test ${r[$i]}?"
        [[ ${l[$i]} -gt ${r[$i]} ]] && exit 0 # Installed version > test version.
        [[ ${l[$i]} -lt ${r[$i]} ]] && exit 1 # Installed version < test version.
    done

    exit 0 # Installed version = test version.
else
    echo "Invalid version number found for command: $Program"
    exit 99
fi

echo "testver - Unreachable code has been reached!"
exit 255
2
WinEunuuchs2Unix