Wie vergleiche ich zwei Zeichenfolgen im punktgetrennten Versionsformat in Bash?


176

Gibt es eine Möglichkeit, solche Zeichenfolgen mit Bash zu vergleichen, z. B.: 2.4.5Und 2.8und 2.4.5.1?


4
Nein, mach es nicht mit bc. Es ist Text, keine Zahlen. 2.1 < 2.10würde auf diese Weise scheitern.
Viraptor

Antworten:


200

Hier ist eine reine Bash-Version, für die keine externen Dienstprogramme erforderlich sind:

#!/bin/bash
vercomp () {
    if [[ $1 == $2 ]]
    then
        return 0
    fi
    local IFS=.
    local i ver1=($1) ver2=($2)
    # fill empty fields in ver1 with zeros
    for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
    do
        ver1[i]=0
    done
    for ((i=0; i<${#ver1[@]}; i++))
    do
        if [[ -z ${ver2[i]} ]]
        then
            # fill empty fields in ver2 with zeros
            ver2[i]=0
        fi
        if ((10#${ver1[i]} > 10#${ver2[i]}))
        then
            return 1
        fi
        if ((10#${ver1[i]} < 10#${ver2[i]}))
        then
            return 2
        fi
    done
    return 0
}

testvercomp () {
    vercomp $1 $2
    case $? in
        0) op='=';;
        1) op='>';;
        2) op='<';;
    esac
    if [[ $op != $3 ]]
    then
        echo "FAIL: Expected '$3', Actual '$op', Arg1 '$1', Arg2 '$2'"
    else
        echo "Pass: '$1 $op $2'"
    fi
}

# Run tests
# argument table format:
# testarg1   testarg2     expected_relationship
echo "The following tests should pass"
while read -r test
do
    testvercomp $test
done << EOF
1            1            =
2.1          2.2          <
3.0.4.10     3.0.4.2      >
4.08         4.08.01      <
3.2.1.9.8144 3.2          >
3.2          3.2.1.9.8144 <
1.2          2.1          <
2.1          1.2          >
5.6.7        5.6.7        =
1.01.1       1.1.1        =
1.1.1        1.01.1       =
1            1.0          =
1.0          1            =
1.0.2.0      1.0.2        =
1..0         1.0          =
1.0          1..0         =
EOF

echo "The following test should fail (test the tester)"
testvercomp 1 1 '>'

Führen Sie die Tests aus:

$ . ./vercomp
The following tests should pass
Pass: '1 = 1'
Pass: '2.1 < 2.2'
Pass: '3.0.4.10 > 3.0.4.2'
Pass: '4.08 < 4.08.01'
Pass: '3.2.1.9.8144 > 3.2'
Pass: '3.2 < 3.2.1.9.8144'
Pass: '1.2 < 2.1'
Pass: '2.1 > 1.2'
Pass: '5.6.7 = 5.6.7'
Pass: '1.01.1 = 1.1.1'
Pass: '1.1.1 = 1.01.1'
Pass: '1 = 1.0'
Pass: '1.0 = 1'
Pass: '1.0.2.0 = 1.0.2'
Pass: '1..0 = 1.0'
Pass: '1.0 = 1..0'
The following test should fail (test the tester)
FAIL: Expected '>', Actual '=', Arg1 '1', Arg2 '1'

2
Können Sie die Lizenz dieses Code-Snippets explizit angeben? Code sieht perfekt aus, aber ich bin nicht sicher, ob ich ihn in einem AGPLv3-Lizenzprojekt verwenden kann.
Kamil Dziedzic

4
@KamilDziedzic: Die Lizenzbedingungen finden Sie unten auf dieser Seite (und den meisten anderen).
Bis auf weiteres angehalten.

4
gnu.org/licenses/license-list.html#ccbysa Please don't use it for software or documentation, since it is incompatible with the GNU GPL : / aber +1 für großartigen Code
Kamil Dziedzic

3
Dies schlägt fehl '1.4rc2> 1.3.3'.
Beachten Sie

1
@SalimaneAdjaoMoustapha: Es ist nicht für diese Art von Versionszeichenfolge ausgelegt. Ich sehe hier keine anderen Antworten, die diesen Vergleich verarbeiten können.
Bis auf weiteres angehalten.

139

Wenn Sie coreutils-7 haben (in Ubuntu Karmic, aber nicht Jaunty), sollte Ihr sortBefehl eine -VOption (Versionssortierung) haben, mit der Sie den Vergleich durchführen können:

verlte() {
    [  "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ]
}

verlt() {
    [ "$1" = "$2" ] && return 1 || verlte $1 $2
}

verlte 2.5.7 2.5.6 && echo "yes" || echo "no" # no
verlt 2.4.10 2.4.9 && echo "yes" || echo "no" # no
verlt 2.4.8 2.4.10 && echo "yes" || echo "no" # yes
verlte 2.5.6 2.5.6 && echo "yes" || echo "no" # yes
verlt 2.5.6 2.5.6 && echo "yes" || echo "no" # no

5
Schöne Lösung. Für Mac OSX-Benutzer können Sie GNU Coreutils gsort verwenden. Das gibt es bei Homebrew : brew install coreutils. Dann sollte das Obige nur geändert werden, um gsort zu verwenden.
Justsee

Ich habe es in einem Skript in Ubuntu präzise zum Laufen gebracht, indem ich -e aus dem Echo entfernt habe.
Hannes R.

2
Funktioniert nicht mit zB Busybox auf einem eingebetteten Linux-System, da Busyboxsort keine -VOption hat.
Craig McQueen

3
Es ist besser zu verwenden printfals echo -e.
Phk

4
GNU sorthat auch -Coder --check=silent, damit Sie schreiben können verlte() { printf '%s\n%s' "$1" "$2" | sort -C -V }; und streng weniger prüfen, als einfacher gemacht wird als verlt() { ! verlte "$2" "$1" }.
Toby Speight

60

Es gibt wahrscheinlich keinen allgemein korrekten Weg, um dies zu erreichen. Wenn Sie versuchen, Versionen im Debian-Paketsystem zu vergleichen, versuchen Sie esdpkg --compare-versions <first> <relation> <second>.


8
Verwendung: dpkg --compare-versions "1.0" "lt" "1.2"bedeutet 1,0 weniger als 1,2. Das Vergleichsergebnis $?ist 0if true, sodass Sie es direkt nach der ifAnweisung verwenden können.
KrisWebDev

48

Die GNU-Sortierung hat eine Option:

printf '2.4.5\n2.8\n2.4.5.1\n' | sort -V

gibt:

2.4.5
2.4.5.1
2.8

2
Die Frage scheint nach der Sortierung der Version zu sein. Bedenken Sie:echo -e "2.4.10\n2.4.9" | sort -n -t.
Kanaka

2
Dies numerisch zu sortieren ist nicht richtig. Sie müssten zuerst mindestens die Zeichenfolgen normalisieren.
Frankc

3
Funktioniert nicht mit zB Busybox auf einem eingebetteten Linux-System, da Busyboxsort keine -VOption hat.
Craig McQueen

Es ist erwähnenswert, dass, wenn die Versionsnummer irgendetwas sein kann, es besser ist, sie im Formular zu verwenden printf '%s\n' "2.4.5" "2.8" "2.4.5.1" | sort -V.
Phk

Wie in einer anderen Antwort erwähnt , funktioniert dies nur mit coreutils 7+.
ivan_pozdeev

35

Wenn Sie die Anzahl der Felder kennen, können Sie -kn, n verwenden und eine supereinfache Lösung erhalten

echo '2.4.5
2.8
2.4.5.1
2.10.2' | sort -t '.' -k 1,1 -k 2,2 -k 3,3 -k 4,4 -g

2.4.5
2.4.5.1
2.8
2.10.2

4
vier Jahre zu spät zur Party, aber meine Lieblingslösung bei weitem :)
LOAS

Ja, die -tOption akzeptiert nur Registerkarten mit nur einem Zeichen. Andernfalls 2.4-r9würde dies auch funktionieren. Was für eine Schande: /
Scottysseus

1
Für Solaris kompat musste ich ändern -gzu -n. Gibt es einen Grund, warum nicht für dieses Beispiel? Nebenbei bemerkt ... um einen Typvergleich "größer als" durchzuführen, können Sie überprüfen, ob die gewünschte Sortierung mit der tatsächlichen Sortierung übereinstimmt ... z . B. desired="1.9\n1.11"; actual="$(echo -e $desired |sort -t '.' -k 1,1 -k 2,2 -g)";und dann überprüfen if [ "$desired" = "$actual" ].
Tresf

23

Dies gilt für höchstens 4 Felder in der Version.

$ function ver { printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' ' '); }
$ [ $(ver 10.9) -lt $(ver 10.10) ] && echo hello  
hello

3
Für den Fall, dass die Version auch 5 Felder haben könnte, könnte das oben printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' '\n' | head -n 4)
Gesagte

2
Ich bin mir nicht sicher, ob alles für alle Versionen von Bash gilt, aber in meinem Fall fehlt nach der letzten runden Klammer ein Semikolon.
Holger Brandl

1
@robinst Um head -nzu arbeiten, musste ich zutr '.' '\n'
Victor Sergienko

Das Semikolon wurde hinzugefügt.
Codeforester

1
@OleksiiChekulaiev Rohrausgabe, trdurch sed 's/\(^\| \)0\([0-9][0-9]*\)/\1\2/g'die das erledigt wird (
ziemlich

21
function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }

Als solches verwendet:

if [ $(version $VAR) -ge $(version "6.2.0") ]; then
    echo "Version is up to date"
fi

(von https://apple.stackexchange.com/a/123408/11374 )


2
Dieser ist der Verwendung des oben vorgeschlagenen Standard-Bash-Drucks weit überlegen. Es verarbeitet Versionen wie "1.09" korrekt, die von normalem printf nicht verarbeitet werden können, da "09 keine korrekte Nummer ist". Außerdem werden führende Nullen automatisch entfernt, was großartig ist, da führende Nullen manchmal zu Vergleichsfehlern führen können.
Oleksii Chekulaiev

8

Sie können aufgeteilt auf rekursiv .und vergleichen , wie in den folgenden Algorithmus, aus genommen ist hier . Es gibt 10 zurück, wenn die Versionen identisch sind, 11, wenn Version 1 größer als Version 2 ist, und 9, wenn dies nicht der Fall ist.

#!/bin/bash
do_version_check() {

   [ "$1" == "$2" ] && return 10

   ver1front=`echo $1 | cut -d "." -f -1`
   ver1back=`echo $1 | cut -d "." -f 2-`

   ver2front=`echo $2 | cut -d "." -f -1`
   ver2back=`echo $2 | cut -d "." -f 2-`

   if [ "$ver1front" != "$1" ] || [ "$ver2front" != "$2" ]; then
       [ "$ver1front" -gt "$ver2front" ] && return 11
       [ "$ver1front" -lt "$ver2front" ] && return 9

       [ "$ver1front" == "$1" ] || [ -z "$ver1back" ] && ver1back=0
       [ "$ver2front" == "$2" ] || [ -z "$ver2back" ] && ver2back=0
       do_version_check "$ver1back" "$ver2back"
       return $?
   else
           [ "$1" -gt "$2" ] && return 11 || return 9
   fi
}    

do_version_check "$1" "$2"

Quelle


6

Wenn es nur darum geht zu wissen, ob eine Version niedriger als eine andere ist, habe ich geprüft, ob sort --version-sortsich die Reihenfolge meiner Versionszeichenfolgen ändert:

    string="$1
$2"
    [ "$string" == "$(sort --version-sort <<< "$string")" ]

5

Ich habe eine Funktion implementiert, die dieselben Ergebnisse wie Dennis Williamsons zurückgibt, jedoch weniger Zeilen verwendet. Zunächst wird eine Überprüfung der geistigen Gesundheit durchgeführt, die dazu führt 1..0, dass seine Tests fehlschlagen (was ich argumentieren würde) , soll der Fall sein) , aber alle seine anderen Tests bestehen , mit diesem Code:

#!/bin/bash
version_compare() {
    if [[ $1 =~ ^([0-9]+\.?)+$ && $2 =~ ^([0-9]+\.?)+$ ]]; then
        local l=(${1//./ }) r=(${2//./ }) s=${#l[@]}; [[ ${#r[@]} -gt ${#l[@]} ]] && s=${#r[@]}

        for i in $(seq 0 $((s - 1))); do
            [[ ${l[$i]} -gt ${r[$i]} ]] && return 1
            [[ ${l[$i]} -lt ${r[$i]} ]] && return 2
        done

        return 0
    else
        echo "Invalid version number given"
        exit 1
    fi
}

Es funktioniert nicht ... Es glaubt, dass 1.15 weniger als 1.8.1 ist.
Carlo Wood

5

Hier ist eine einfache Bash-Funktion, die keine externen Befehle verwendet. Es funktioniert für Versionszeichenfolgen mit bis zu drei numerischen Teilen - weniger als 3 sind ebenfalls in Ordnung. Es kann leicht für mehr erweitert werden. Es implementiert =, <, <=, >, >=, und !=Bedingungen.

#!/bin/bash
vercmp() {
    version1=$1 version2=$2 condition=$3

    IFS=. v1_array=($version1) v2_array=($version2)
    v1=$((v1_array[0] * 100 + v1_array[1] * 10 + v1_array[2]))
    v2=$((v2_array[0] * 100 + v2_array[1] * 10 + v2_array[2]))
    diff=$((v2 - v1))
    [[ $condition = '='  ]] && ((diff == 0)) && return 0
    [[ $condition = '!=' ]] && ((diff != 0)) && return 0
    [[ $condition = '<'  ]] && ((diff >  0)) && return 0
    [[ $condition = '<=' ]] && ((diff >= 0)) && return 0
    [[ $condition = '>'  ]] && ((diff <  0)) && return 0
    [[ $condition = '>=' ]] && ((diff <= 0)) && return 0
    return 1
}

Hier ist der Test:

for tv1 in '*' 1.1.1 2.5.3 7.3.0 0.5.7 10.3.9 8.55.32 0.0.1; do
    for tv2 in 3.1.1 1.5.3 4.3.0 0.0.7 0.3.9 11.55.32 10.0.0 '*'; do
      for c in '=' '>' '<' '>=' '<=' '!='; do
        vercmp "$tv1" "$tv2" "$c" && printf '%s\n' "$tv1 $c $tv2 is true" || printf '%s\n' "$tv1 $c $tv2 is false"
      done
    done
done

Eine Teilmenge der Testausgabe:

<snip>

* >= * is true
* <= * is true
* != * is true
1.1.1 = 3.1.1 is false
1.1.1 > 3.1.1 is false
1.1.1 < 3.1.1 is true
1.1.1 >= 3.1.1 is false
1.1.1 <= 3.1.1 is true
1.1.1 != 3.1.1 is true
1.1.1 = 1.5.3 is false
1.1.1 > 1.5.3 is false
1.1.1 < 1.5.3 is true
1.1.1 >= 1.5.3 is false
1.1.1 <= 1.5.3 is true
1.1.1 != 1.5.3 is true
1.1.1 = 4.3.0 is false
1.1.1 > 4.3.0 is false

<snip>

5
  • Funktion V - reine Bash-Lösung, keine externen Dienstprogramme erforderlich.
  • Unterstützt = == != < <= >und>= (lexikografisch).
  • Optionaler Vergleich der Endbuchstaben: 1.5a < 1.5b
  • Ungleicher Längenvergleich: 1.6 > 1.5b
  • Liest von links nach rechts : if V 1.5 '<' 1.6; then ....

<>

# Sample output
# Note: ++ (true) and __ (false) mean that V works correctly.

++ 3.6 '>' 3.5b
__ 2.5.7 '<=' 2.5.6
++ 2.4.10 '<' 2.5.9
__ 3.0002 '>' 3.0003.3
++ 4.0-RC2 '>' 4.0-RC1

<>

function V() # $1-a $2-op $3-$b
# Compare a and b as version strings. Rules:
# R1: a and b : dot-separated sequence of items. Items are numeric. The last item can optionally end with letters, i.e., 2.5 or 2.5a.
# R2: Zeros are automatically inserted to compare the same number of items, i.e., 1.0 < 1.0.1 means 1.0.0 < 1.0.1 => yes.
# R3: op can be '=' '==' '!=' '<' '<=' '>' '>=' (lexicographic).
# R4: Unrestricted number of digits of any item, i.e., 3.0003 > 3.0000004.
# R5: Unrestricted number of items.
{
  local a=$1 op=$2 b=$3 al=${1##*.} bl=${3##*.}
  while [[ $al =~ ^[[:digit:]] ]]; do al=${al:1}; done
  while [[ $bl =~ ^[[:digit:]] ]]; do bl=${bl:1}; done
  local ai=${a%$al} bi=${b%$bl}

  local ap=${ai//[[:digit:]]} bp=${bi//[[:digit:]]}
  ap=${ap//./.0} bp=${bp//./.0}

  local w=1 fmt=$a.$b x IFS=.
  for x in $fmt; do [ ${#x} -gt $w ] && w=${#x}; done
  fmt=${*//[^.]}; fmt=${fmt//./%${w}s}
  printf -v a $fmt $ai$bp; printf -v a "%s-%${w}s" $a $al
  printf -v b $fmt $bi$ap; printf -v b "%s-%${w}s" $b $bl

  case $op in
    '<='|'>=' ) [ "$a" ${op:0:1} "$b" ] || [ "$a" = "$b" ] ;;
    * )         [ "$a" $op "$b" ] ;;
  esac
}

Code erklärt

Zeile 1 : Lokale Variablen definieren:

  • a, op, b- Vergleichsoperanden und Operator, das heißt, "3.6"> "3.5a".
  • al, bl- Buchstabenschwänze von aund b, initialisiert auf das Endstück, dh "6" und "5a".

Zeilen 2, 3 : Ziffern links von den Endelementen, sodass nur noch Buchstaben übrig sind, z. B. "" und "a".

Zeile 4 : Rechte Trimmbuchstaben von aund b, um nur die Folge numerischer Elemente als lokale Variablen zu belassenai und zubi dh "3.6" und "3.5" zu belassen. Bemerkenswertes Beispiel: "4.01-RC2"> "4.01-RC1" ergibt ai = "4.01" al = "- RC2" und bi = "4.01" bl = "- RC1".

Zeile 6 : Lokale Variablen definieren:

  • ap, bp- Null Rechtspolster für aiund bi. Starten Sie durch die Zwischenelement - Punkte nur zu halten, von welcher Nummer die Anzahl der Elemente gleich aund bjeweils.

Zeile 7 : Fügen Sie dann nach jedem Punkt "0" hinzu, um Füllmasken zu erstellen.

Zeile 9 : Lokale Variablen:

  • w - Artikelbreite
  • fmt - zu berechnende printf-Formatzeichenfolge
  • x - vorübergehend
  • Mit IFS=.Bash werden variable Werte bei '.' Aufgeteilt.

Zeile 10 : Berechnen Sie wdie maximale Elementbreite, die zum Ausrichten von Elementen für den lexikografischen Vergleich verwendet wird. In unserem Beispiel ist w = 2.

Zeile 11 : Erstellen der printf Ausrichtungsformat , das von einzelnen Zeichen zu ersetzen , $a.$bmit %${w}s, das heißt, "3.6"> "3.5a" Ausbeute "% 2s% 2s% 2s% 2s".

Zeile 12 : "printf -v a" legt den Wert der Variablen fest a. Dies entspricht a=sprintf(...)in vielen Programmiersprachen. Beachten Sie, dass hier durch Wirkung von IFS =. die Argumente, printfdie in einzelne Elemente aufgeteilt werden sollen.

Bei den ersten printfElementen awerden links Leerzeichen aufgefüllt, während genügend "0" -Elemente angehängt werden, bpum sicherzustellen, dass die resultierende Zeichenfolge asinnvoll mit einer ähnlich formatierten verglichen werden kann b.

Beachten Sie, dass wir anhängen bp- nicht apan, aiweil apund bpmöglicherweise unterschiedliche Längen haben, so dass dies zu aund bmit gleichen Längen führt.

Mit dem zweiten printffügen wir den Brief Teil alan amit genügend Polsterung zu aussagekräftigen Vergleich zu ermöglichen. Jetzt aist zum Vergleich bereit mit b.

Zeile 13 : Wie Zeile 12, jedoch für b.

Zeile 15 : Aufteilen von Vergleichsfällen zwischen nicht integrierten ( <=und >=) und integrierten Operatoren.

Zeile 16 : Wenn der Vergleichsoperator ist, <=testen Sie auf a<b or a=b- jeweils>= a<b or a=b

Zeile 17 : Test für eingebaute Vergleichsoperatoren.

<>

# All tests

function P { printf "$@"; }
function EXPECT { printf "$@"; }
function CODE { awk $BASH_LINENO'==NR{print " "$2,$3,$4}' "$0"; }
P 'Note: ++ (true) and __ (false) mean that V works correctly.\n'

V 2.5    '!='  2.5      && P + || P _; EXPECT _; CODE
V 2.5    '='   2.5      && P + || P _; EXPECT +; CODE
V 2.5    '=='  2.5      && P + || P _; EXPECT +; CODE

V 2.5a   '=='  2.5b     && P + || P _; EXPECT _; CODE
V 2.5a   '<'   2.5b     && P + || P _; EXPECT +; CODE
V 2.5a   '>'   2.5b     && P + || P _; EXPECT _; CODE
V 2.5b   '>'   2.5a     && P + || P _; EXPECT +; CODE
V 2.5b   '<'   2.5a     && P + || P _; EXPECT _; CODE
V 3.5    '<'   3.5b     && P + || P _; EXPECT +; CODE
V 3.5    '>'   3.5b     && P + || P _; EXPECT _; CODE
V 3.5b   '>'   3.5      && P + || P _; EXPECT +; CODE
V 3.5b   '<'   3.5      && P + || P _; EXPECT _; CODE
V 3.6    '<'   3.5b     && P + || P _; EXPECT _; CODE
V 3.6    '>'   3.5b     && P + || P _; EXPECT +; CODE
V 3.5b   '<'   3.6      && P + || P _; EXPECT +; CODE
V 3.5b   '>'   3.6      && P + || P _; EXPECT _; CODE

V 2.5.7  '<='  2.5.6    && P + || P _; EXPECT _; CODE
V 2.4.10 '<'   2.4.9    && P + || P _; EXPECT _; CODE
V 2.4.10 '<'   2.5.9    && P + || P _; EXPECT +; CODE
V 3.4.10 '<'   2.5.9    && P + || P _; EXPECT _; CODE
V 2.4.8  '>'   2.4.10   && P + || P _; EXPECT _; CODE
V 2.5.6  '<='  2.5.6    && P + || P _; EXPECT +; CODE
V 2.5.6  '>='  2.5.6    && P + || P _; EXPECT +; CODE
V 3.0    '<'   3.0.3    && P + || P _; EXPECT +; CODE
V 3.0002 '<'   3.0003.3 && P + || P _; EXPECT +; CODE
V 3.0002 '>'   3.0003.3 && P + || P _; EXPECT _; CODE
V 3.0003.3 '<' 3.0002   && P + || P _; EXPECT _; CODE
V 3.0003.3 '>' 3.0002   && P + || P _; EXPECT +; CODE

V 4.0-RC2 '>' 4.0-RC1   && P + || P _; EXPECT +; CODE
V 4.0-RC2 '<' 4.0-RC1   && P + || P _; EXPECT _; CODE

4

Ich verwende Embedded Linux (Yocto) mit BusyBox. BusyBoxsort hat keine -VOption (aber BusyBoxexpr match kann reguläre Ausdrücke ausführen ). Also brauchte ich einen Bash-Versionsvergleich, der mit dieser Einschränkung funktionierte.

Ich habe Folgendes gemacht (ähnlich wie Dennis Williamsons Antwort ), um es mit einem Algorithmus vom Typ "natürliche Art" zu vergleichen. Es teilt die Zeichenfolge in numerische Teile und nicht numerische Teile auf. Es vergleicht die numerischen Teile numerisch ( 10ist also größer als 9) und vergleicht die nicht numerischen Teile als einfachen ASCII-Vergleich.

ascii_frag() {
    expr match "$1" "\([^[:digit:]]*\)"
}

ascii_remainder() {
    expr match "$1" "[^[:digit:]]*\(.*\)"
}

numeric_frag() {
    expr match "$1" "\([[:digit:]]*\)"
}

numeric_remainder() {
    expr match "$1" "[[:digit:]]*\(.*\)"
}

vercomp_debug() {
    OUT="$1"
    #echo "${OUT}"
}

# return 1 for $1 > $2
# return 2 for $1 < $2
# return 0 for equal
vercomp() {
    local WORK1="$1"
    local WORK2="$2"
    local NUM1="", NUM2="", ASCII1="", ASCII2=""
    while true; do
        vercomp_debug "ASCII compare"
        ASCII1=`ascii_frag "${WORK1}"`
        ASCII2=`ascii_frag "${WORK2}"`
        WORK1=`ascii_remainder "${WORK1}"`
        WORK2=`ascii_remainder "${WORK2}"`
        vercomp_debug "\"${ASCII1}\" remainder \"${WORK1}\""
        vercomp_debug "\"${ASCII2}\" remainder \"${WORK2}\""

        if [ "${ASCII1}" \> "${ASCII2}" ]; then
            vercomp_debug "ascii ${ASCII1} > ${ASCII2}"
            return 1
        elif [ "${ASCII1}" \< "${ASCII2}" ]; then
            vercomp_debug "ascii ${ASCII1} < ${ASCII2}"
            return 2
        fi
        vercomp_debug "--------"

        vercomp_debug "Numeric compare"
        NUM1=`numeric_frag "${WORK1}"`
        NUM2=`numeric_frag "${WORK2}"`
        WORK1=`numeric_remainder "${WORK1}"`
        WORK2=`numeric_remainder "${WORK2}"`
        vercomp_debug "\"${NUM1}\" remainder \"${WORK1}\""
        vercomp_debug "\"${NUM2}\" remainder \"${WORK2}\""

        if [ -z "${NUM1}" -a -z "${NUM2}" ]; then
            vercomp_debug "blank 1 and blank 2 equal"
            return 0
        elif [ -z "${NUM1}" -a -n "${NUM2}" ]; then
            vercomp_debug "blank 1 less than non-blank 2"
            return 2
        elif [ -n "${NUM1}" -a -z "${NUM2}" ]; then
            vercomp_debug "non-blank 1 greater than blank 2"
            return 1
        fi

        if [ "${NUM1}" -gt "${NUM2}" ]; then
            vercomp_debug "num ${NUM1} > ${NUM2}"
            return 1
        elif [ "${NUM1}" -lt "${NUM2}" ]; then
            vercomp_debug "num ${NUM1} < ${NUM2}"
            return 2
        fi
        vercomp_debug "--------"
    done
}

Es kann kompliziertere Versionsnummern wie z

  • 1.2-r3 gegen 1.2-r4
  • 1.2rc3 gegen 1.2r4

Beachten Sie, dass für einige der Eckfälle in Dennis Williamsons Antwort nicht das gleiche Ergebnis zurückgegeben wird . Bestimmtes:

1            1.0          <
1.0          1            >
1.0.2.0      1.0.2        >
1..0         1.0          >
1.0          1..0         <

Aber das sind Eckfälle, und ich denke, die Ergebnisse sind immer noch vernünftig.


4
$ for OVFTOOL_VERSION in "4.2.0" "4.2.1" "5.2.0" "3.2.0" "4.1.9" "4.0.1" "4.3.0" "4.5.0" "4.2.1" "30.1.0" "4" "5" "4.1" "4.3"
> do
>   if [ $(echo "$OVFTOOL_VERSION 4.2.0" | tr " " "\n" | sort --version-sort | head -n 1) = 4.2.0 ]; then 
>     echo "$OVFTOOL_VERSION is >= 4.2.0"; 
>   else 
>     echo "$OVFTOOL_VERSION is < 4.2.0"; 
>   fi
> done
4.2.0 is >= 4.2.0
4.2.1 is >= 4.2.0
5.2.0 is >= 4.2.0
3.2.0 is < 4.2.0
4.1.9 is < 4.2.0
4.0.1 is < 4.2.0
4.3.0 is >= 4.2.0
4.5.0 is >= 4.2.0
4.2.1 is >= 4.2.0
30.1.0 is >= 4.2.0
4 is < 4.2.0
5 is >= 4.2.0
4.1 is < 4.2.0
4.3 is >= 4.2.0

1
Mit GNU sort können Sie verwenden --check=silent, ohne dass testdies erforderlich ist: if printf '%s\n%s' 4.2.0 "$OVFTOOL_VERSION" | sort --version-sort -C
Toby Speight

Vielen Dank an @Toby Speight
djna

4

Dies ist auch eine pure bashLösung, da printf eine eingebaute Bash ist.

function ver()
# Description: use for comparisons of version strings.
# $1  : a version string of form 1.2.3.4
# use: (( $(ver 1.2.3.4) >= $(ver 1.2.3.3) )) && echo "yes" || echo "no"
{
    printf "%02d%02d%02d%02d" ${1//./ }
}

Begrenzt ... Funktioniert nur für reine Zahlen unter 100 mit genau 4 Werten. Netter Versuch!
Anthony

2

Für alte Version / Busybox sort. Einfache Form liefern ungefähr Ergebnisse und funktionieren oft.

sort -n

Dies ist besonders nützlich bei Versionen, die Alpha-Symbole wie enthalten

10.c.3
10.a.4
2.b.5

1

Wie wäre es damit? Scheint zu funktionieren?

checkVersion() {
subVer1=$1
subVer2=$2

[ "$subVer1" == "$subVer2" ] && echo "Version is same"
echo "Version 1 is $subVer1"
testVer1=$subVer1
echo "Test version 1 is $testVer1"
x=0
while [[ $testVer1 != "" ]]
do
  ((x++))
  testVer1=`echo $subVer1|cut -d "." -f $x`
  echo "testVer1 now is $testVer1"
  testVer2=`echo $subVer2|cut -d "." -f $x`
  echo "testVer2 now is $testVer2"
  if [[ $testVer1 -gt $testVer2 ]]
  then
    echo "$ver1 is greater than $ver2"
    break
  elif [[ "$testVer2" -gt "$testVer1" ]]
  then
    echo "$ver2 is greater than $ver1"
    break
  fi
  echo "This is the sub verion for first value $testVer1"
  echo "This is the sub verion for second value $testVer2"
done
}

ver1=$1
ver2=$2
checkVersion "$ver1" "$ver2"

1

Hier ist eine weitere reine Bash-Lösung ohne externe Anrufe:

#!/bin/bash

function version_compare {

IFS='.' read -ra ver1 <<< "$1"
IFS='.' read -ra ver2 <<< "$2"

[[ ${#ver1[@]} -gt ${#ver2[@]} ]] && till=${#ver1[@]} || till=${#ver2[@]}

for ((i=0; i<${till}; i++)); do

    local num1; local num2;

    [[ -z ${ver1[i]} ]] && num1=0 || num1=${ver1[i]}
    [[ -z ${ver2[i]} ]] && num2=0 || num2=${ver2[i]}

    if [[ $num1 -gt $num2 ]]; then
        echo ">"; return 0
    elif
       [[ $num1 -lt $num2 ]]; then
        echo "<"; return 0
    fi
done

echo "="; return 0
}

echo "${1} $(version_compare "${1}" "${2}") ${2}"

Und es gibt eine noch einfachere Lösung, wenn Sie sicher sind, dass die fraglichen Versionen keine führenden Nullen nach dem ersten Punkt enthalten:

#!/bin/bash

function version_compare {

local ver1=${1//.}
local ver2=${2//.}


    if [[ $ver1 -gt $ver2 ]]; then
        echo ">"; return 0
    elif    
       [[ $ver1 -lt $ver2 ]]; then
        echo "<"; return 0
    fi 

echo "="; return 0
}

echo "${1} $(version_compare "${1}" "${2}") ${2}"

Dies funktioniert für etwas wie 1.2.3 gegen 1.3.1 gegen 0.9.7, aber nicht für 1.2.3 gegen 1.2.3.0 oder 1.01.1 gegen 1.1.1


Zweite Version kann in4.4.4 > 44.3
yairchu

1

Hier ist eine Verfeinerung der Top-Antwort (Dennis's), die präziser ist und ein anderes Rückgabewertschema verwendet, um die Implementierung von <= und> = mit einem einzigen Vergleich zu vereinfachen. Es vergleicht auch alles nach dem ersten Zeichen nicht in [0-9.] Lexikographisch, also 1.0rc1 <1.0rc2.

# Compares two tuple-based, dot-delimited version numbers a and b (possibly
# with arbitrary string suffixes). Returns:
# 1 if a<b
# 2 if equal
# 3 if a>b
# Everything after the first character not in [0-9.] is compared
# lexicographically using ASCII ordering if the tuple-based versions are equal.
compare-versions() {
    if [[ $1 == $2 ]]; then
        return 2
    fi
    local IFS=.
    local i a=(${1%%[^0-9.]*}) b=(${2%%[^0-9.]*})
    local arem=${1#${1%%[^0-9.]*}} brem=${2#${2%%[^0-9.]*}}
    for ((i=0; i<${#a[@]} || i<${#b[@]}; i++)); do
        if ((10#${a[i]:-0} < 10#${b[i]:-0})); then
            return 1
        elif ((10#${a[i]:-0} > 10#${b[i]:-0})); then
            return 3
        fi
    done
    if [ "$arem" '<' "$brem" ]; then
        return 1
    elif [ "$arem" '>' "$brem" ]; then
        return 3
    fi
    return 2
}

Hier ist eine positive Bewertung, weil sie hier verwendet wird
Codebling

1

Ich habe noch eine weitere Komparatorfunktion implementiert. Dieser hatte zwei spezifische Anforderungen: (i) Ich wollte nicht, dass die Funktion durch Verwendung von return 1sondern fehlschlägt echo; (ii) Da wir Versionen aus einem Git-Repository abrufen, sollte "1.0" größer als "1.0.2" sein, was bedeutet, dass "1.0" aus dem Trunk stammt.

function version_compare {
  IFS="." read -a v_a <<< "$1"
  IFS="." read -a v_b <<< "$2"

  while [[ -n "$v_a" || -n "$v_b" ]]; do
    [[ -z "$v_a" || "$v_a" -gt "$v_b" ]] && echo 1 && return
    [[ -z "$v_b" || "$v_b" -gt "$v_a" ]] && echo -1 && return

    v_a=("${v_a[@]:1}")
    v_b=("${v_b[@]:1}")
  done

  echo 0
}

Fühlen Sie sich frei zu kommentieren und Verbesserungen vorzuschlagen.


1

Sie können die Versions- CLI verwenden, um die Einschränkungen der Version zu überprüfen

$ version ">=1.0, <2.0" "1.7"
$ go version | version ">=1.9"

Beispiel für ein Bash-Skript:

#!/bin/bash

if `version -b ">=9.0.0" "$(gcc --version)"`; then
  echo "gcc version satisfies constraints >=9.0.0"
else
  echo "gcc version doesn't satisfies constraints >=9.0.0"
fi

0

Ich bin auf dieses Problem gestoßen und habe es gelöst, um eine zusätzliche (und kürzere und einfachere) Antwort hinzuzufügen ...

Erster Hinweis: Der erweiterte Shell-Vergleich ist fehlgeschlagen, wie Sie vielleicht bereits wissen ...

    if [[ 1.2.0 < 1.12.12 ]]; then echo true; else echo false; fi
    false

Mit der Sortierung -t '.'- g (oder der Sortierung -V, wie von Kanaka erwähnt) zum Bestellen von Versionen und zum einfachen Vergleich von Bash-Strings habe ich eine Lösung gefunden. Die Eingabedatei enthält Versionen in den Spalten 3 und 4, die ich vergleichen möchte. Dies durchläuft die Liste und identifiziert eine Übereinstimmung oder wenn eine größer als die andere ist. Ich hoffe, dies kann immer noch jedem helfen, der dies mit Bash so einfach wie möglich machen möchte.

while read l
do
    #Field 3 contains version on left to compare (change -f3 to required column).
    kf=$(echo $l | cut -d ' ' -f3)
    #Field 4 contains version on right to compare (change -f4 to required column).
    mp=$(echo $l | cut -d ' ' -f4)

    echo 'kf = '$kf
    echo 'mp = '$mp

    #To compare versions m.m.m the two can be listed and sorted with a . separator and the greater version found.
    gv=$(echo -e $kf'\n'$mp | sort -t'.' -g | tail -n 1)

    if [ $kf = $mp ]; then 
        echo 'Match Found: '$l
    elif [ $kf = $gv ]; then
        echo 'Karaf feature file version is greater '$l
    elif [ $mp = $gv ]; then
        echo 'Maven pom file version is greater '$l
   else
       echo 'Comparison error '$l
   fi
done < features_and_pom_versions.tmp.txt

Vielen Dank an Barrys Blog für die Sortieridee ... ref: http://bkhome.org/blog/?viewDetailed=02199


0
### the answer is does we second argument is higher
function _ver_higher {
        ver=`echo -ne "$1\n$2" |sort -Vr |head -n1`
        if [ "$2" == "$1" ]; then
                return 1
        elif [ "$2" == "$ver" ]; then
                return 0
        else
                return 1
        fi
}

if _ver_higher $1 $2; then
        echo higher
else
        echo same or less
fi

Es ist ziemlich einfach und klein.


Dies wird brechen , wenn es Schrägstriche in den Versionen sind, besser ersetzen echo -ne "$1\n$2"mit printf '%s\n ' "$1" "$2". Es ist auch besser, $()anstelle der Backtics zu verwenden.
Phk

0

Dank Dennis 'Lösung können wir sie erweitern, um Vergleichsoperatoren'> ',' <',' = ',' == ',' <= 'und'> = 'zu ermöglichen.

# compver ver1 '=|==|>|<|>=|<=' ver2
compver() { 
    local op
    vercomp $1 $3
    case $? in
        0) op='=';;
        1) op='>';;
        2) op='<';;
    esac
    [[ $2 == *$op* ]] && return 0 || return 1
}

Wir können dann Vergleichsoperatoren in folgenden Ausdrücken verwenden:

compver 1.7 '<=' 1.8
compver 1.7 '==' 1.7
compver 1.7 '=' 1.7

und testen Sie nur das Richtig / Falsch des Ergebnisses, wie:

if compver $ver1 '>' $ver2; then
    echo "Newer"
fi

0

Hier ist eine weitere reine Bash-Version, die eher kleiner als die akzeptierte Antwort ist. Es wird nur geprüft, ob eine Version kleiner oder gleich einer "Mindestversion" ist, und es werden alphanumerische Sequenzen lexikografisch überprüft, was häufig zu einem falschen Ergebnis führt ("Schnappschuss" ist nicht später als "Veröffentlichung", um ein allgemeines Beispiel zu nennen). . Es wird gut für Dur / Moll funktionieren.

is_number() {
    case "$BASH_VERSION" in
        3.1.*)
            PATTERN='\^\[0-9\]+\$'
            ;;
        *)
            PATTERN='^[0-9]+$'
            ;;
    esac

    [[ "$1" =~ $PATTERN ]]
}

min_version() {
    if [[ $# != 2 ]]
    then
        echo "Usage: min_version current minimum"
        return
    fi

    A="${1%%.*}"
    B="${2%%.*}"

    if [[ "$A" != "$1" && "$B" != "$2" && "$A" == "$B" ]]
    then
        min_version "${1#*.}" "${2#*.}"
    else
        if is_number "$A" && is_number "$B"
        then
            [[ "$A" -ge "$B" ]]
        else
            [[ ! "$A" < "$B" ]]
        fi
    fi
}

0

Ein anderer Ansatz (modifizierte Version von @joynes), der gepunktete Versionen vergleicht, wie in der Frage gestellt
(dh "1.2", "2.3.4", "1.0", "1.10.1" usw.).
Die maximale Anzahl von Positionen muss im Voraus bekannt sein. Der Ansatz erwartet maximal 3 Versionspositionen.

expr $(printf "$1\n$2" | sort -t '.' -k 1,1 -k 2,2 -k 3,3 -g | sed -n 2p) != $2

Anwendungsbeispiel:

expr $(printf "1.10.1\n1.7" | sort -t '.' -k 1,1 -k 2,2 -k 3,3 -g | sed -n 2p) != "1.7"

Rückgabe: 1, da 1.10.1 größer als 1.7 ist

expr $(printf "1.10.1\n1.11" | sort -t '.' -k 1,1 -k 2,2 -k 3,3 -g | sed -n 2p) != "1.11"

Rückgabe: 0, da 1.10.1 niedriger als 1.11 ist


0

Hier ist eine reine Bash-Lösung, die Revisionen unterstützt (z. B. '1.0-r1'), basierend auf der Antwort von Dennis Williamson . Es kann leicht geändert werden, um Dinge wie '-RC1' zu unterstützen oder die Version aus einer komplexeren Zeichenfolge zu extrahieren, indem der reguläre Ausdruck geändert wird.

Einzelheiten zur Implementierung finden Sie in den In-Code-Kommentaren und / oder aktivieren Sie den enthaltenen Debug-Code:

#!/bin/bash

# Compare two version strings [$1: version string 1 (v1), $2: version string 2 (v2)]
# Return values:
#   0: v1 == v2
#   1: v1 > v2
#   2: v1 < v2
# Based on: https://stackoverflow.com/a/4025065 by Dennis Williamson
function compare_versions() {

    # Trivial v1 == v2 test based on string comparison
    [[ "$1" == "$2" ]] && return 0

    # Local variables
    local regex="^(.*)-r([0-9]*)$" va1=() vr1=0 va2=() vr2=0 len i IFS="."

    # Split version strings into arrays, extract trailing revisions
    if [[ "$1" =~ ${regex} ]]; then
        va1=(${BASH_REMATCH[1]})
        [[ -n "${BASH_REMATCH[2]}" ]] && vr1=${BASH_REMATCH[2]}
    else
        va1=($1)
    fi
    if [[ "$2" =~ ${regex} ]]; then
        va2=(${BASH_REMATCH[1]})
        [[ -n "${BASH_REMATCH[2]}" ]] && vr2=${BASH_REMATCH[2]}
    else
        va2=($2)
    fi

    # Bring va1 and va2 to same length by filling empty fields with zeros
    (( ${#va1[@]} > ${#va2[@]} )) && len=${#va1[@]} || len=${#va2[@]}
    for ((i=0; i < len; ++i)); do
        [[ -z "${va1[i]}" ]] && va1[i]="0"
        [[ -z "${va2[i]}" ]] && va2[i]="0"
    done

    # Append revisions, increment length
    va1+=($vr1)
    va2+=($vr2)
    len=$((len+1))

    # *** DEBUG ***
    #echo "TEST: '${va1[@]} (?) ${va2[@]}'"

    # Compare version elements, check if v1 > v2 or v1 < v2
    for ((i=0; i < len; ++i)); do
        if (( 10#${va1[i]} > 10#${va2[i]} )); then
            return 1
        elif (( 10#${va1[i]} < 10#${va2[i]} )); then
            return 2
        fi
    done

    # All elements are equal, thus v1 == v2
    return 0
}

# Test compare_versions [$1: version string 1, $2: version string 2, $3: expected result]
function test_compare_versions() {
    local op
    compare_versions "$1" "$2"
    case $? in
        0) op="==" ;;
        1) op=">" ;;
        2) op="<" ;;
    esac
    if [[ "$op" == "$3" ]]; then
        echo -e "\e[1;32mPASS: '$1 $op $2'\e[0m"
    else
        echo -e "\e[1;31mFAIL: '$1 $3 $2' (result: '$1 $op $2')\e[0m"
    fi
}

echo -e "\nThe following tests should pass:"
while read -r test; do
    test_compare_versions $test
done << EOF
1            1            ==
2.1          2.2          <
3.0.4.10     3.0.4.2      >
4.08         4.08.01      <
3.2.1.9.8144 3.2          >
3.2          3.2.1.9.8144 <
1.2          2.1          <
2.1          1.2          >
5.6.7        5.6.7        ==
1.01.1       1.1.1        ==
1.1.1        1.01.1       ==
1            1.0          ==
1.0          1            ==
1.0.2.0      1.0.2        ==
1..0         1.0          ==
1.0          1..0         ==
1.0-r1       1.0-r3       <
1.0-r9       2.0          <
3.0-r15      3.0-r9       >
...-r1       ...-r2       <
2.0-r1       1.9.8.21-r2  >
1.0          3.8.9.32-r   <
-r           -r3          <
-r3          -r           >
-r3          -r3          ==
-r           -r           ==
0.0-r2       0.0.0.0-r2   ==
1.0.0.0-r2   1.0-r2       ==
0.0.0.1-r7   -r9          >
0.0-r0       0            ==
1.002.0-r6   1.2.0-r7     <
001.001-r2   1.1-r2       ==
5.6.1-r0     5.6.1        ==
EOF

echo -e "\nThe following tests should fail:"
while read -r test; do
    test_compare_versions $test
done << EOF
1            1            >
3.0.5-r5     3..5-r5      >
4.9.21-r3    4.8.22-r9    <
1.0-r        1.0-r1       ==
-r           1.0-r        >
-r1          0.0-r1       <
-r2          0-r2         <
EOF

echo -e "\nThe following line should be empty (local variables test):"
echo "$op $regex $va1 $vr1 $va2 $vr2 $len $i $IFS"

0

Wow ... das ist ganz unten auf der Liste einer alten Frage, aber ich denke, das ist eine ziemlich elegante Antwort. Konvertieren Sie zuerst jede durch Punkte getrennte Version mithilfe der Shell-Parametererweiterung in ein eigenes Array (siehe Shell-Parametererweiterung ).

v1="05.2.3"     # some evil examples that work here
v2="7.001.0.0"

declare -a v1_array=(${v1//./ })
declare -a v2_array=(${v2//./ })

Jetzt haben die beiden Arrays die Versionsnummer als numerische Zeichenfolge in Prioritätsreihenfolge. Viele der oben genannten Lösungen führen Sie von dort aus, aber alles ergibt sich aus der Beobachtung, dass die Versionszeichenfolge nur eine Ganzzahl mit einer beliebigen Basis ist. Wir können testen, ob die erste ungleiche Ziffer gefunden wurde (wie es strcmp für Zeichen in einer Zeichenfolge tut).

compare_version() {
  declare -a v1_array=(${1//./ })
  declare -a v2_array=(${2//./ })

  while [[ -nz $v1_array ]] || [[ -nz $v2_array ]]; do
    let v1_val=${v1_array:-0}  # this will remove any leading zeros
    let v2_val=${v2_array:-0}
    let result=$((v1_val-v2_val))

    if (( result != 0 )); then
      echo $result
      return
    fi

    v1_array=("${v1_array[@]:1}") # trim off the first "digit". it doesn't help
    v2_array=("${v2_array[@]:1}")
  done

  # if we get here, both the arrays are empty and neither has been numerically
  # different, which is equivalent to the two versions being equal

  echo 0
  return
}

Dies gibt eine negative Zahl wieder, wenn die erste Version kleiner als die zweite ist, eine Null, wenn sie gleich sind, und eine positive Zahl, wenn die erste Version größer ist. Einige Ausgaben:

$ compare_version 1 1.2
-2
$ compare_version "05.1.3" "5.001.03.0.0.0.1"
-1
$ compare_version "05.1.3" "5.001.03.0.0.0"
0
$ compare_version "05.1.3" "5.001.03.0"
0
$ compare_version "05.1.3" "5.001.30.0"
-27
$ compare_version "05.2.3" "7.001.0.0"
-2
$ compare_version "05.1.3" "5.001.30.0"
-27
$ compare_version "7.001.0.0" "05.1.3"
2

Entartete Fälle wie ".2" oder "3.0". funktioniert nicht (undefinierte Ergebnisse) und wenn nicht numerische Zeichen neben dem '.' vorhanden sind. es könnte fehlschlagen (nicht getestet), wird aber sicherlich undefiniert sein. Dies sollte daher mit einer Desinfektionsfunktion oder einer entsprechenden Überprüfung auf gültige Formatierung kombiniert werden. Ich bin mir auch sicher, dass dies mit einigen Optimierungen ohne zu viel zusätzliches Gepäck robuster gemacht werden könnte.


0
function version_compare () {
  function sub_ver () {
    local len=${#1}
    temp=${1%%"."*} && indexOf=`echo ${1%%"."*} | echo ${#temp}`
    echo -e "${1:0:indexOf}"
  }
  function cut_dot () {
    local offset=${#1}
    local length=${#2}
    echo -e "${2:((++offset)):length}"
  }
  if [ -z "$1" ] || [ -z "$2" ]; then
    echo "=" && exit 0
  fi
  local v1=`echo -e "${1}" | tr -d '[[:space:]]'`
  local v2=`echo -e "${2}" | tr -d '[[:space:]]'`
  local v1_sub=`sub_ver $v1`
  local v2_sub=`sub_ver $v2`
  if (( v1_sub > v2_sub )); then
    echo ">"
  elif (( v1_sub < v2_sub )); then
    echo "<"
  else
    version_compare `cut_dot $v1_sub $v1` `cut_dot $v2_sub $v2`
  fi
}

### Usage:

version_compare "1.2.3" "1.2.4"
# Output: <

Das Guthaben geht an @Shellman

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.