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.
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.
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
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
Il y a plusieurs façons d'aborder ce que vous voulez réaliser.
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é.
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.
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.
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
.
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 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