1. Verwenden Sie $BASH_VERSION

1. Verwenden Sie $BASH_VERSION

Ich muss testen, ob die Bash-Versionsnummer >= einer bestimmten Nummer ist. Ich habe zum Beispiel:

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

Um assoziative Arrays verwenden zu können, muss die Bash-Versionsnummer >=4 sein.

In meinem Bash-Skript möchte ich auf möglichst elegante/effiziente/lesbare Weise einen Einzeiler-Test einfügen, aber auch andere Ansätze sind zulässig.

Antwort1

Versuchen:

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

BASH_VERSINFOist eine schreibgeschützte Array-Variable, deren Mitglieder Versionsinformationen für diese Instanz von Bash enthalten. Da sie mit Bash 2.0 eingeführt wurde, wird sie wahrscheinlich von allen Bash-Versionen unterstützt, denen Sie begegnen. Aus Sicherheitsgründen fügen wir jedoch einen Standardwert von of 0für alle früheren Bash-Versionen ein, für die diese Variable nicht gesetzt ist.

Extrahieren von Versionsinformationen aus anderen Programmen

Sie haben nach LibreOffice, Python, Kernel usw. gefragt.

LibreOffice erstellt Versionsinformationen, die wie folgt aussehen:

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

So extrahieren Sie die Versionsnummer:

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

Für Python:

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

Um die Kernelversion zu erhalten, verwenden Sie uname:

$ uname -r
4.9.0-2-amd64

Antwort2

Anstatt die Versionsnummern zu vergleichen, können Sie die Funktion selbst direkt testen. declare -Agibt zurück 2(zumindest in Bash 3.2), wenn es nicht erkannt wird -A, testen Sie also darauf (es gibt auch einen Fehler aus):

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

( declare -A varschlägt auch fehl, wenn vares sich um ein nicht-assoziatives Array handelt, also unsetzuerst.)

Obwohl ich nicht wirklich davon ausgehe, dass irgendjemand Funktionen in Bash zurückportieren wird, ist es im Allgemeinen sinnvoller, nach den Funktionen zu suchen, nicht nach den Versionen. Sogar im Fall von Bash könnte jemand eine Version mit nur eingeschränkten Funktionen kompilieren ...


Der allgemeinere Fall des Testens von Versionsnummern besteht aus zwei Teilen: 1) wie man die richtige Versionsnummer zum Testen findet und 2) wie man sie mit einem anderen Wert vergleicht.

Der erste ist der schwierigere. Viele Programme geben ihre Versionsnummer mit einem Befehlszeilenflag wie --versionoder an -v, aber das Ausgabeformat variiert und das programmgesteuerte Auswählen der Versionsnummer kann schwierig sein. Dann gibt es noch das Problem, dass möglicherweise mehrere Versionen desselben Programms gleichzeitig installiert sind.

Die zweite Möglichkeit hängt von einigen Kenntnissen über das Format der Versionsnummern ab. dpkgkann vergleichenVersionsnummern im Debian-Stil(was meiner Meinung nach beinhaltetsemverTypversionen als Teilmenge):

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

Oder kombinieren Sie einfach die oben genannten Punkte:

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

Antwort3

Es gibt mehrere Möglichkeiten, Ihr Ziel zu erreichen.

1. Verwenden Sie $BASH_VERSION

Es reicht aus, einfach zu sehen, was in der $BASH_VERSIONVariable steht. Persönlich würde ich Subshell folgendermaßen verwenden:

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

Beachten Sie, dass <<<die Syntax für here-doc nicht portierbar ist, wenn Sie sie mit verwenden möchten. /bin/shUnter Ubuntu ist dies Dash, auf einem anderen System kann es sich jedoch um etwas anderes handeln.

Alternativ kann man es auch über Case- oder If-Anweisungen machen. Ich persönlich würde es so machen:

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

Wahrscheinlich aus Gründen der Portabilität sollten Sie zunächst prüfen, ob eine solche Variable überhaupt festgelegt ist, und zwar mit etwas wie[ -n $BASH_VERSION ]

Dies kann vollständig als Funktion umgeschrieben werden, die in einem Skript verwendet werden kann. Etwa so:

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

Das ist kein Einzeiler, obwohl es viel besser ist. Qualität vor Quantität.

2. Überprüfen Sie, was installiert ist

Dafür müssen Sie die Ausgabe apt-cache policywie folgt filtern

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

dpkg-querykann auch mit etwas Filterung über nützlich sein awk.

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

Beachten Sie, dass dies nicht portierbar ist, da es Ihnen nichts nützt, wenn auf einem System (beispielsweise RHEL oder FreeBSD) dpkgoder nicht installiert ist .apt

3. Verwenden Sie set -e, um das Skript zu beenden, wenn ein Fehler auftritt

Eine Möglichkeit, dies zu umgehen, besteht darin, einfach mit der Verwendung assoziativer Arrays fortzufahren und das Skript zu beenden, wenn bashsie nicht verwendet werden können. set -eDie folgende Zeile #!/bin/bashermöglicht das Beenden des Skripts, wenn das Skript kein assoziatives Array verwenden kann.

Dazu müssen Sie dem Benutzer explizit mitteilen: „Hey, Sie benötigen unbedingt Bash Version 4.3 oder höher, sonst funktioniert das Skript nicht.“ Die Verantwortung liegt dann beim Benutzer, obwohl manche argumentieren könnten, dass dies kein wirklich guter Ansatz für die Softwareentwicklung ist.

4. Geben Sie alle Hoffnung auf und schreiben Sie portable, POSIX-kompatible Skripte

bashSkripte sind nicht portierbar, da ihre Syntax nicht mit der Bourne-Shell kompatibel ist. Wenn das Skript, das Sie schreiben, auf einer Reihe verschiedener Systeme verwendet werden soll, nicht nur auf Ubuntu, dann geben Sie alle Hoffnung auf und suchen Sie nach Möglichkeiten, etwas anderes als assoziative Arrays zu verwenden. Dazu könnten zwei Arrays oder das Parsen einer Konfigurationsdatei gehören. Erwägen Sie auch den Wechsel zu einer anderen Sprache, Perl oder Python, deren Syntax zumindest portabler ist als bash.

Antwort4

Einzeiler ist nicht möglich, aber ein Bash-Skript ist möglich

Ich habe ein Skript entwickelt, das auf Antworten in Stack Overflow zurückgreift. Eine dieser Antworten führte dazu, dass ein Dell-Mitarbeiter im Jahr 2004 Versionsnummernvergleiche für die DKMS-Anwendung schrieb.

Der Code

Das folgende Bash-Skript muss mit dem Befehl als ausführbar markiert werden chmod a+x script-name. Ich verwende den Namen /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

verwandte Informationen