2010-08-18 9 views
8

Sürümlerin biçimi - X.X.X.X.
Burada X - numarası.
İki sürümü karşılaştırmanın en iyi yolu nedir?Bazı ürünlerin sürümleri unix ksh kabuğunda nasıl karşılaştırılır?

compareVersions() 
{ 
    VER_1=$1 
    VER_2=$2 

    print -R "$VER_1"| IFS=. read v1_1 v1_2 v1_3 v1_4 
    print -R "$VER_2"| IFS=. read v2_1 v2_2 v2_3 v2_4 

    RESULT="0" 

    if [[ "${v1_1}" -lt "${v2_1}" ]] 
    then 
    RESULT="-1" 
    elif [[ "${v1_1}" -gt "${v2_1}" ]] 
    then 
    RESULT="1" 
    elif [[ "${v1_2}" -lt "${v2_2}" ]] 
    then 
    RESULT="-1" 
    elif [[ "${v1_2}" -gt "${v2_2}" ]] 
    then 
    RESULT="1" 
    elif [[ "${v1_3}" -lt "${v2_3}" ]] 
    then 
    RESULT="-1" 
    elif [[ "${v1_3}" -gt "${v2_3}" ]] 
    then 
    RESULT="1" 
    elif [[ "${v1_4}" -lt "${v2_4}" ]] 
    then 
    RESULT="-1" 
    elif [[ "${v1_4}" -gt "${v2_4}" ]] 
    then 
    RESULT="1" 
    fi 

    echo "$RESULT" 
} 

Ama bunu sevmiyorum - bu çok basittir:
kod aşağıdaki kullanın.
Belki sürümleri karşılaştırmak için doğru yol var mı?

+1

Bunun Bash yerine ksh olmadığından emin misiniz? Bash 'print' komutuna sahip değildir ve' read' (okuma) 'ya giremezsiniz. –

+0

Evet - bu ksh. Etiketlerimi sabitledim. –

+2

"okuyabildiğini okuyamazsın" - tabi ki yapabilirsin. printf "abc \ n" | {okuma x; printf "$ x \ n var"; } ' –

cevap

11

Saf Bash/Ksh: Eğer kabuk komut Perl kullanarak hile Eğer

compareVersions() 
{ 
    typeset IFS='.' 
    typeset -a v1=($1) 
    typeset -a v2=($2) 
    typeset n diff 

    for ((n=0; n<4; n+=1)); do 
    diff=$((v1[n]-v2[n])) 
    if [ $diff -ne 0 ] ; then 
     [ $diff -le 0 ] && echo '-1' || echo '1' 
     return 
    fi 
    done 
    echo '0' 
} # ---------- end of function compareVersions ---------- 
+1

+1 Tüm değişkenlerinizi yerel yapmalısınız. –

+0

Haklısınız. Sadece tamir edildi. –

+0

fgm script için teşekkürler!Sadece bir inek olduğum ve bir şeyi tam olarak yapma ihtiyacım olduğu için "$ diff -le 0" "$ diff -lt 0" olmalıdır. Önceki şartlar nedeniyle $ diff, bu noktada asla 0 olmayacağından. – ptsw

7

Belki awk kullanıyor musunuz?

echo $VER_1 $VER2 | \ 
awk '{ split($1, a, "."); 
     split($2, b, "."); 
     for (i = 1; i <= 4; i++) 
      if (a[i] < b[i]) { 
       x =-1; 
       break; 
      } else if (a[i] > b[i]) { 
       x = 1; 
       break; 
      } 
     print x; 
    }' 

Bunu yapmak için mükemmel bir yol yoktur. Gösterildiği gibi, bash da numaralar için dizi/döngü kullanabilirsiniz.

+1

Bu," sort -V' isn "gibi uyumluluk için tercih edilen yöntemim bence Yaygın olarak yeterince desteklenir ve 'awk' kullanmak, belirli yerleşik özelliklere olan ihtiyacı ortadan kaldırır. – Haravikk

+1

Bunu yapmak için 'for' döngüsünü' (i = 1;! X && i <= 4; ++ i) x = (a [i] b [i])? 1: 0); – ldav1s

2

, bu yerleşik oluyor handling of version strings dize karşılaştırma operatörleri ile deneyin:

V1=1.1.3; V2=1.1 
echo $(perl -e '($x,$y)[email protected]; print $x cmp $y' $V1 $V2) 

Ayrıca yapabilirdi Perl değişkenleri ile ve sadece vardiya kullanın:

ersions> 10. Yani onun yerine bu deneyebilirsiniz: Açıkçası

perl -e '($a,$b)[email protected]; for ($a,$b) {s/(\d+)/sprintf "%5d", $1/ge}; print $a cmp $b;' 12.1.3 9.0.2 
"% 5d" nin sprintf hatta sürümü 99999 kadar, Firefox için çalışacak emin olmaktır

... :-)

Ayrıca gt, lt, ge ve le gibi diğer Perl dizisi operatörlerini de kullanabilirsiniz.

4

Sen sürümleri ile satırları sıralamak ve çıkış karşı sürümle uyumlu sort -V kullanabilirsiniz:

% cat sorttest 
#!/bin/sh 

version_lt() { 
    echo "$1\n$2" | sort -V | head -n 1 | grep -q "$1" 
} 

display_versioncmp() { 
    version_lt "$1" "$2" && echo "$1 < $2" || echo "$1 > $2" 
} 

X="1.2.3" 
Y="11.2.3" 
Z="1.22.3" 

display_versioncmp "$X" "$Y" 
display_versioncmp "$Y" "$X" 
display_versioncmp "$X" "$Z" 
display_versioncmp "$Z" "$X" 
display_versioncmp "$Z" "$Y" 
display_versioncmp "$Y" "$Z" 

% ./sorttest 
1.2.3 < 11.2.3 
11.2.3 > 1.2.3 
1.2.3 < 1.22.3 
1.22.3 > 1.2.3 
1.22.3 < 11.2.3 
11.2.3 > 1.22.3 
+2

Ne yazık ki, her platformun bashı 'sort -V' değil. (Ör., Mac olmayabilir.) – kcrisman

+0

Komut dosyası doğru değil. 3.22.3> 11.2.3 gibi tüm durumları çözmezse eğer giriş 3 ve 11 ise kesinlikle 11 daha yüksek bir versiyona sahiptir ancak betik 3'ün daha yüksek bir versiyonu vardır. –

+1

@AnandChoubey tür sürümünüz var mı? Benimkiyle (Ubuntu 12.04'tür) tümü beklendiği gibi çalışır: 3.22.3> 1.2.3 3.22.3 <11.2.3 # sort --version sort (GNU coreutils) 8.13 – timurb

0

bu sorunu vardı ve çözme sonra daha iyi bir yanıt zaten mevcut olup olmadığını görmek için baktı. Sürümüm farklı uzunluklu sürüm dizelerini karşılaştırmaya izin veriyor ve version_ge "$ version" "1.2.3.4" ise

'da olduğu gibi "büyük veya eşit" operatör olarak kullanılması gereken version_ge() işlevidir. ; o zaman ...

#!/bin/sh 

# Usage: split "<word list>" <variable1> <variable2>... 
# Split a string of $IFS seperated words into individual words, and 
# assign them to a list of variables. If there are more words than 
# variables then all the remaining words are put in the last variable; 
# use a dummy last variable to collect any unwanted words. 
# Any variables for which there are no words are cleared. 
# eg. split 'hello Fred this is Bill' greeting who extra 
# sets greeting=hello who=Fred extra="this is Bill" 
# and split "$list" word list # "pops" the first word from a list 
split() 
{ 
    # Prefix local names with the function name to try to avoid conflicts 
    # local split_wordlist 
    split_wordlist="$1" 
    shift 
    read "[email protected]" <<EOF-split-end-of-arguments 
${split_wordlist} 
EOF-split-end-of-arguments 
} 


# Usage: version_ge v1 v2 
# Where v1 and v2 are multi-part version numbers such as 12.5.67 
# Missing .<number>s on the end of a version are treated as .0, & leading 
# zeros are not significant, so 1.2 == 1.2.0 == 1.2.0.0 == 01.2 == 1.02 
# Returns true if v1 >= v2, false if v1 < v2 
version_ge() 
{ 
    # Prefix local names with the function name to try to avoid conflicts 
    # local version_ge_1 version_ge_2 version_ge_a version_ge_b 
    # local version_ge_save_ifs 
    version_ge_v1="$1" 
    version_ge_v2="$2" 

    version_ge_save_ifs="$IFS" 
    while test -n "${version_ge_v1}${version_ge_v2}"; do 
     IFS="." 
     split "$version_ge_v1" version_ge_a version_ge_v1 
     split "$version_ge_v2" version_ge_b version_ge_v2 
     IFS="$version_ge_save_ifs" 
     #echo " compare $version_ge_a $version_ge_b" 
     test "0$version_ge_a" -gt "0$version_ge_b" && return 0 # v1>v2: true 
     test "0$version_ge_a" -lt "0$version_ge_b" && return 1 # v1<v2:false 
    done 
    # version strings are both empty & no differences found - must be equal. 
    return 0 # v1==v2: true 
}