18 votes

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

J'ai besoin de 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 les tableaux associatifs, le numéro de version de bash doit être >=4.

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

22voto

user221266 Points 11

Essayez :

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

BASH_VERSINFO est une variable de type tableau en lecture seule dont les membres contiennent des informations sur la version de cette instance de bash. Puisqu'elle a été introduite avec bash 2.0, elle est probablement supportée 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 n'est pas définie.

Extraction d'informations sur la version d'autres programmes

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

LibreOffice produit des informations sur la version qui ressemblent à ceci :

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

10voto

ilkkachu Points 1499

Au lieu de comparer les numéros de version, vous pourriez tester directement la fonctionnalité elle-même. declare -A retours 2 (au moins dans Bash 3.2) s'il ne reconnaît pas la fonction -A Il s'agit donc d'un test (qui génère é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 d'abord).

Bien que je ne suppose pas vraiment que quelqu'un va rétroporter des fonctionnalités dans Bash, il est généralement plus approprié de vérifier les fonctionnalités, et non les versions. Même dans le cas de Bash, quelqu'un pourrait compiler une version avec des fonctionnalités limitées...


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

La première est la plus difficile. De nombreux programmes indiquent leur numéro de version à l'aide d'un indicateur de ligne de commande tel que --version o -v mais le format de sortie varie et il peut s'avérer difficile de déterminer le numéro de version par programme. En outre, il est possible que plusieurs versions d'un même programme soient 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 à la manière de Debian (ce qui, je pense, inclut semoir comme sous-ensemble) :

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

Ou, tout simplement, de 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

5voto

Sergiy Kolodyazhnyy Points 97292

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

1. Utiliser $BASH_VERSION

Il suffit de voir ce qu'il y a dedans $BASH_VERSION variable. Personnellement, j'utiliserais subshell comme suit :

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

Il convient de noter que <<< pour here-doc n'est pas portable, si vous voulez l'utiliser avec /bin/sh qui est Dash sur Ubuntu et peut être autre chose sur un autre système

L'autre solution consiste à utiliser l'instruction case ou l'instruction if. Personnellement, c'est ce que je ferais :

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

Pour des raisons de portabilité, vous devriez probablement vérifier si une telle variable est définie en premier lieu avec quelque chose comme [ -n $BASH_VERSION ]

Ce totalement peut être réécrit comme une fonction à utiliser dans un script. Quelque chose de l'ordre 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

Il ne s'agit pas d'un one-liner, même si celui-ci est bien meilleur. La qualité prime sur la quantité.

2. Vérifier ce qui est installé

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

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

dpkg-query peut également s'avérer utile avec un certain 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 de dpkg o apt installé sur un système (par exemple, RHEL ou FreeBSD), il ne vous sera d'aucune utilité.

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

Une façon de contourner ce problème est d'utiliser des tableaux associatifs et d'abandonner lorsque bash ne peuvent pas les utiliser. set -e ligne ci-dessous #!/bin/bash permet au script de quitter si le script ne peut pas utiliser un tableau associatif.

Cela vous obligera à dire explicitement à l'utilisateur : "Hé, vous avez vraiment besoin de la version 4.3 ou supérieure de bash, sinon le script ne fonctionnera pas". La responsabilité incombe alors à l'utilisateur, bien que certains puissent affirmer qu'il ne s'agit pas là d'une bonne approche du développement logiciel.

4. Abandonner tout espoir et écrire des scripts portables et conformes à POSIX.

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

2voto

WinEunuuchs2Unix Points 91128

Le one-liner n'est pas possible mais un script bash l'est.

J'ai développé un script qui s'appuie sur les réponses de 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 script 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

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X