it-swarm.com.de

BASH Vergleich der Versionsnummern

Hey Leute, ich habe dieses Skript, das sicherstellen sollte, dass die aktuelle PHP -Version der Benutzer sich in einem bestimmten Bereich befindet. Obwohl es funktionieren sollte, gibt es irgendwo einen Fehler, der vermuten lässt, dass die Version außerhalb des gültigen Bereichs liegt. Könnte jemand einen Blick darauf werfen und mir sagen, was ich tun kann, um das Problem zu beheben?

function version { echo "[email protected]" | gawk -F. '{ printf("%d.%d.%d\n", $1,$2,$3); }'; }

phpver=`php -v |grep -Eow '^PHP [^ ]+' |gawk '{ print $2 }'`

if [ $(version $phpver) > $(version 5.2.13) ] || [ $(version $phpver) < $(version 5.2.13) ]; then
  echo "PHP Version $phpver must be between 5.2.13 - 5.3.15"
  exit
fi
19
ehime

So vergleichen Sie Versionen.

mit sort -V:

function version_gt() { test "$(printf '%s\n' "[email protected]" | sort -V | head -n 1)" != "$1"; }

Verwendungsbeispiel:

first_version=5.100.2
second_version=5.1.2
if version_gt $first_version $second_version; then
     echo "$first_version is greater than $second_version !"
fi

pro:

  • solide Möglichkeit, ausgefallene Versionsstrings zu vergleichen:
    • unterstützt eine beliebige Länge von Unterteilen (z. B. 1.3alpha.2.dev2> 1.1?)
    • unterstützt alpha-betical sort (dh: 1α <1β2)
    • große Version unterstützen (zB: 1.10003939209329320932> 1.2039209378273789273?)
  • kann leicht geändert werden, um n Argumente zu unterstützen. (leaved als Übung;))
    • normalerweise sehr nützlich mit 3 Argumenten: (dh: 1.2 <meine_Version <2.7)

Nachteile:

  • verwendet viele verschiedene Aufrufe zu verschiedenen Programmen. Also ist es nicht so effizient.
  • verwendet eine ziemlich neuere Version von sort und ist möglicherweise nicht auf Ihrem System verfügbar. (überprüfe mit man sort)

ohne sort -V:

## each separate version number must be less than 3 digit wide !
function version { echo "[email protected]" | gawk -F. '{ printf("%03d%03d%03d\n", $1,$2,$3); }'; }

Verwendungsbeispiel:

first_version=5.100.2
second_version=5.1.2
if [ "$(version "$first_version")" -gt "$(version "$second_version")" ]; then
     echo "$first_version is greater than $second_version !"
fi

pro:

  • schnellere Lösung, da nur ein Teilprozess aufgerufen wird
  • viel mehr kompatible Lösung.

Nachteile:

  • ganz genau, Versionsstring muss:
    • haben nur Version mit 1, 2 oder 3 Teilen. (ausgenommen '2.1.3.1')
    • jeder Teil muss nur numerisch sein (ausgenommen '3.1a').
    • jedes Teil darf nicht größer als 999 sein (ausgenommen '1.20140417')

Kommentare zu Ihrem Skript:

Ich kann nicht sehen, wie es funktionieren könnte: 

  • wie in einem Kommentar angegeben, sind > und < sehr spezielle Shell-Zeichen und sollten durch -gt und -lt ersetzt werden.
  • selbst wenn Sie die Zeichen ersetzt haben, können Sie die Versionsnummern nicht vergleichen, als wären sie Ganzzahlen oder Float. Auf meinem System ist beispielsweise die PHP-Version 5.5.9-1ubuntu4.

Aber Ihre Funktion version() ist bereits ziemlich geschickt geschrieben und kann Ihnen helfen, indem Sie das klassische Problem umgehen, dass beim Sortieren alphabetisch keine Zahlen numerisch sortiert werden (alphabetisch 1 <11 <2, was numerisch falsch ist). Aber Achtung: Willkürlich große Zahlen werden von bash nicht unterstützt (versuchen Sie, unter 32 Bit zu bleiben, wenn Sie die Kompatibilität mit 32-Bit-Systemen anstreben, so dass dies 9-stellige lange Zahlen wäre). Also habe ich Ihren Code geändert (in der zweiten Methode NICHT mit sort -V), um nur drei Ziffern für jeden Teil der Versionszeichenfolge zu erzwingen.

EDIT: angewendete @phk-Verbesserung, da es merklich klüger ist und einen Unterprozessaufruf in der ersten Version mit sort entfernt. Vielen Dank.

55
vaab

Es gibt die Möglichkeit für Deb-Distributionen:

dpkg --compare-versions <version> <relation> <version>

Zum Beispiel:

dpkg --compare-versions "0.0.4" "gt" "0.0.3"
if [ $? -eq "0" ]; then echo "YES"; else echo "NO"; fi
7
Andrey

Hier ist eine andere Lösung, die:

  • führt außer tr keine externen Befehle aus
  • hat keine Einschränkung für die Anzahl der Teile in der Versionszeichenfolge
  • kann Versionszeichenfolgen mit unterschiedlicher Anzahl von Teilen vergleichen

Beachten Sie, dass es sich um Bash-Code handelt, der Array-Variablen verwendet.

compare_versions()
{
    local v1=( $(echo "$1" | tr '.' ' ') )
    local v2=( $(echo "$2" | tr '.' ' ') )
    local len="$(max "${#v1[*]}" "${#v2[*]}")"
    for ((i=0; i<len; i++))
    do
        [ "${v1[i]:-0}" -gt "${v2[i]:-0}" ] && return 1
        [ "${v1[i]:-0}" -lt "${v2[i]:-0}" ] && return 2
    done
    return 0
}

Die Funktion gibt zurück:

  • 0 wenn Versionen gleich sind (btw: 1.2 == 1.2.0)
  • 1, wenn die 1. Version größer/neuer ist
  • 2 wenn die 2. Version größer/neuer ist

Allerdings ist # 1 - es ist eine zusätzliche Funktion erforderlich (die Funktion min kann jedoch trotzdem verwendet werden):

min()
{
    local m="$1"
    for n in "[email protected]"
    do
        [ "$n" -lt "$m" ] && m="$n"
    done
    echo "$m"
}

Allerdings # 2 - Versionszeichenfolgen können nicht mit alphanumerischen Teilen verglichen werden (obwohl dies eigentlich nicht schwierig ist, hinzugefügt zu werden).

2
mato

Es führt einen lexikalischen Vergleich durch. Verwenden Sie eine davon:

if [ $(version $phpver) -gt $(version 5.2.13) ] || [ $(version $phpver) -lt $(version 5.2.13) ]; then
if [[ $(version $phpver) > $(version 5.2.13) ]] || [[ $(version $phpver) < $(version 5.2.13) ]]; then
if (( $(version $phpver) > $(version 5.2.13) )) || (( $(version $phpver) < $(version 5.2.13) )); then

Oder machen Sie alles in awk oder einem anderen Werkzeug. Es schreit nach Optimierung. Es scheint auch, dass Sie auch keine Zahlen produzieren, so dass Sie ein ziemlich seltsames Design haben. Normalerweise werden die Versions-Teilzeichenfolgen mit 1000 multipliziert und dann alle aufsummiert, um einen einzigen vergleichbaren Skalar zu erhalten.

2
lynxlynxlynx

Wenn Sie sich in Bash 3 mit einer älteren Version von sort befinden (siehe MacOS ...), habe ich folgendes Hilfsskript erstellt, in das Sie einlesen können (kann auch als Befehl ausgeführt werden):

https://github.com/Unicorn-fail/version_compare

1
Mark Carver

Die folgende Lösung sollte Ihren genauen Bedürfnissen genauer entsprechen. Es kann verwendet werden, um zu testen, ob die Versionszeichenfolge CURRENT zwischen MIN und MAX liegt. Ich gehe davon aus, dass MIN und MAX akzeptable Versionsnummern sind (d. H. MIN <= CURRENT <= MAX und nicht MIN < CURRENT < MAX).

# Usage: version MIN CURRENT MAX
version(){
    local h t v

    [[ $2 = "$1" || $2 = "$3" ]] && return 0

    v=$(printf '%s\n' "[email protected]" | sort -V)
    h=$(head -n1 <<<"$v")
    t=$(tail -n1 <<<"$v")

    [[ $2 != "$h" && $2 != "$t" ]]
}

Zum Beispiel...

if ! version 5.2.13 "$phpver" 5.3.15; then
    echo "PHP Version $phpver must be between 5.2.13 - 5.3.15"
    exit
fi
1
Six

Eine viel sicherere Option zum Testen der PHP CLI-Version ist die Verwendung der PHP-eigenen Funktion version_compare .

#!/bin/bash

MIN_VERSION="7.0.0"
MAX_VERSION="7.1.4"
PHP_VERSION=`php -r 'echo PHP_VERSION;'`

function version_compare() {
    COMPARE_OP=$1;
    TEST_VERSION=$2;
    RESULT=$(php -r 'echo version_compare(PHP_VERSION, "'${TEST_VERSION}'", "'${COMPARE_OP}'") ? "TRUE" : "";')

    test -n "${RESULT}";
}

if ( version_compare "<" "${MIN_VERSION}" || version_compare ">" "${MAX_VERSION}" ); then
    echo "PHP Version ${PHP_VERSION} must be between ${MIN_VERSION} - ${MAX_VERSION}";
    exit 1;
fi

echo "PHP Version ${PHP_VERSION} is good!";
1
ianmjones

Ich habe diese unelegante Funktion vor einiger Zeit für ein ähnliches Problem geschrieben. vers_limit gibt 0 zurück, wenn arg1 kleiner oder gleich arg2 ist, nicht 0, sonst:

vers_limit()
{
VERNEW=$1
VERLMT=$2

CHKNEW=$VERNEW
CHKLMT=$VERLMT

PASSED=

while :
do
        PARTNEW=${CHKNEW%%.*}
        PARTLMT=${CHKLMT%%.*}
        if [[ $PARTNEW -lt $PARTLMT ]]
        then
                PASSED=GOOD
                break
        Elif [[ $PARTNEW -gt $PARTLMT ]]
        then
                PASSED=
                break
        else
                NXTNEW=${CHKNEW#*.}
                if [[ $NXTNEW == $CHKNEW ]]
                then
                        if [[ $NXTNEW == $CHKLMT ]]
                        then
                                PASSED=GOOD
                                break
                        else
                                NXTNEW=0
                        fi
                fi
                NXTLMT=${CHKLMT#*.}
                if [[ $NXTLMT == $CHKLMT ]]
                then
                        NXTLMT=0
                fi
        fi
        CHKNEW=$NXTNEW
        CHKLMT=$NXTLMT
done
test "$PASSED"
}

Dies ist nicht so kompakt wie einige der anderen Lösungen und bietet auch keinen 3-Wege-Status (dh weniger, gleich, größer), obwohl ich glaube, dass man die Argumente ordnen, den Pass/Fail-Status interpretieren kann und/oder zweimal anrufen, um ein beliebiges Ergebnis zu erzielen. Das heißt, vers_limit hat bestimmte Tugenden:

  1. Keine Aufrufe an externe Dienstprogramme wie sort, awk, gawk, tr usw.

  2. Behandelt numerische Versionen beliebiger Größe (bis zur Shell-Grenze Für Ganzzahlberechnungen)

  3. Verarbeitet eine beliebige Anzahl von "gepunkteten" Teilen.

0
oracleif