कैसे बैश में दो अलग-अलग संस्करण प्रारूप में तार की तुलना करें?


176

क्या बैश पर इस तरह के तारों की तुलना करने का कोई तरीका है, जैसे: 2.4.5और 2.8और 2.4.5.1?


4
नहीं, इसके साथ मत करो bc। यह पाठ संख्या नहीं है। 2.1 < 2.10इस तरह से विफल होगा।
विराटपुर

जवाबों:


200

यहाँ एक शुद्ध बैश संस्करण है जिसे किसी भी बाहरी उपयोगिताओं की आवश्यकता नहीं है:

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

परीक्षण चलाएं:

$ . ./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
क्या आप इस कोड स्निपेट का स्पष्ट रूप से लाइसेंस दे सकते हैं? कोड सही लगता है, लेकिन मुझे यकीन नहीं है कि मैं इसे एजीपीएलवी 3 लाइसेंस प्राप्त परियोजना में उपयोग कर सकता हूं।
कामिल डिजिडिज़िक

4
@KamilDziedzic: इस पृष्ठ के नीचे (और अधिकांश अन्य) लाइसेंस शब्द बताए गए हैं।
अगली सूचना तक रोक दिया गया।

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 : / / लेकिन महान कोड के लिए +1
कामिल

3
यह '1.4rc2> 1.3.3' विफल हो जाता है। अल्फ़ान्यूमेरिक संस्करण पर ध्यान दें
सलीमने अदाजो मोवाफ़फा

1
@SalimaneAdjaoMoustapha: यह उस प्रकार के संस्करण स्ट्रिंग को संभालने के लिए डिज़ाइन नहीं किया गया है। मुझे यहाँ कोई अन्य उत्तर नहीं दिखता है जो उस तुलना को संभाल सके।
अगली सूचना तक रोक दिया गया।

139

यदि आपके पास कोरुटिल्स -7 (उबंटू कर्मिक में नहीं बल्कि जोंटी है) तो आपकी sortकमांड में एक -Vविकल्प (संस्करण प्रकार) होना चाहिए जिसका उपयोग आप तुलना करने के लिए कर सकते हैं:

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
अच्छा समाधान है। मैक OSX उपयोगकर्ताओं के लिए, आप GNU Coreutils gsort का उपयोग कर सकते हैं। यह होमब्रे के माध्यम से उपलब्ध है brew install coreutils:। फिर उपरोक्त को सिर्फ gsort का उपयोग करने के लिए संशोधित किया जाना चाहिए।
Justsee

मैं इसे एक स्क्रिप्ट में उबंटू में सटीक काम कर रहा था-ईको से हटाकर।
हेंस आर।

2
व्यस्त लिनक्स सिस्टम पर उदाहरण के लिए व्यस्त बॉक्स के साथ काम नहीं करता है, क्योंकि व्यस्त बॉक्सsort में -Vविकल्प नहीं है ।
क्रेग मैकक्वीन

3
इसके printfबजाय इसका उपयोग करना बेहतर है echo -e
phk

4
GNU sortभी है -Cया --check=silent, इसलिए आप लिख सकते हैं verlte() { printf '%s\n%s' "$1" "$2" | sort -C -V }; और सख्त जाँच की तुलना में कम बस के रूप में किया जाता है verlt() { ! verlte "$2" "$1" }
टोबे स्पाइट

60

इसे प्राप्त करने का कोई सार्वभौमिक सही तरीका नहीं है। यदि आप डेबियन पैकेज सिस्टम में संस्करणों की तुलना करने की कोशिश कर रहे हैंdpkg --compare-versions <first> <relation> <second>.


8
उपयोग: dpkg --compare-versions "1.0" "lt" "1.2"1.2 से कम 1.0 का मतलब है। तुलना परिणाम $?है 0अगर सच तो आप इसे सीधे के बाद का उपयोग कर सकते ifबयान।
क्रिस्बडेव

48

GNU सॉर्ट में इसके लिए एक विकल्प है:

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

देता है:

2.4.5
2.4.5.1
2.8

2
संस्करण प्रकार के बारे में सवाल लगता है। विचार करें:echo -e "2.4.10\n2.4.9" | sort -n -t.
kanaka

2
इसे संख्यात्मक रूप से क्रमबद्ध करना सही नहीं है। आपको कम से कम पहले तार को सामान्य करने की आवश्यकता होगी।
फ्रैंक

3
व्यस्त लिनक्स सिस्टम पर उदाहरण के लिए व्यस्त बॉक्स के साथ काम नहीं करता है, क्योंकि व्यस्त बॉक्सsort में -Vविकल्प नहीं है ।
क्रेग मैकक्वीन

यह ध्यान देने योग्य है कि यदि संस्करण संख्या कुछ भी हो सकती है तो फॉर्म में इसका उपयोग करना बेहतर होगा printf '%s\n' "2.4.5" "2.8" "2.4.5.1" | sort -V
phk

जैसा कि एक अन्य जवाब में कहा गया है , यह केवल साथ काम करता है coreutils 7+
ivan_pozdeev 8

35

वैसे यदि आप जानते हैं कि आप किस क्षेत्र की संख्या का उपयोग कर सकते हैं, - n, n और एक सुपर-सरल समाधान प्राप्त करें

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
पार्टी में चार साल की देरी, लेकिन दूर से मेरा पसंदीदा समाधान :)
LOAS

हाँ, -tविकल्प केवल एकल वर्ण टैब स्वीकार करता है ... अन्यथा, 2.4-r9साथ ही साथ काम करेगा। क्या शर्म की बात है: /
स्कॉटीसियस 14

1
सोलारिस compat के लिए, मैं बदलना पड़ा -gकरने के लिए -n। किसी भी कारण से इस उदाहरण के लिए नहीं? एक साइड-नोट पर ... "तुलना से अधिक" प्रकार की तुलना करने के लिए, आप जांच सकते हैं कि क्या वांछित सॉर्ट वास्तविक सॉर्ट के समान है ... उदाहरण के लिए desired="1.9\n1.11"; actual="$(echo -e $desired |sort -t '.' -k 1,1 -k 2,2 -g)";और फिर सत्यापित करें if [ "$desired" = "$actual" ]
tresf

23

यह संस्करण में अधिकतम 4 क्षेत्रों के लिए है।

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

3
यदि संस्करण में 5 क्षेत्र भी हो सकते हैं, तो उपरोक्त को इस तरह से सुरक्षित किया जा सकता है:printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' '\n' | head -n 4)
4

2
सुनिश्चित नहीं है कि यह सभी बैश के सभी संस्करणों पर लागू होता है, लेकिन मेरे मामले में अंतिम राउंड ब्रैकेट के बाद एक अर्धविराम गायब है।
होल्गर ब्रांडल

1
@robinst head -nकाम करने के लिए, मुझे बदलना पड़ाtr '.' '\n'
विक्टर

अर्धविराम जोड़ा।
codeforester

1
@OleksiiChekulaiev पाइप trउत्पादन sed 's/\(^\| \)0\([0-9][0-9]*\)/\1\2/g'जिसके माध्यम से (बल्कि
अनाड़ी

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

इस तरह से इस्तेमाल किया:

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

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


2
यह ऊपर दिए गए प्रस्ताव के अनुसार डिफ़ॉल्ट बैश प्रिंटफ का उपयोग करने के लिए बहुत बेहतर है। यह "1.09" जैसे संस्करणों को सही ढंग से संसाधित करता है जो कि प्रक्रिया में असमर्थ होने के कारण नियमित रूप से प्रिंटफ होता है क्योंकि "09 एक सही संख्या नहीं है"। यह स्वचालित रूप से अग्रणी शून्य को भी हटा देता है जो महान है क्योंकि कभी-कभी अग्रणी शून्य तुलनात्मक त्रुटियों को जन्म दे सकता है।
ओलेक्सी चीकुइलाव

8

आप पुनरावर्ती को विभाजित कर सकते हैं .और तुलना कर सकते हैं जैसा कि निम्नलिखित एल्गोरिथम में दिखाया गया है, यहां से लिया गया है । यह 10 रिटर्न देता है यदि संस्करण समान हैं, 11 यदि संस्करण 1 संस्करण 2 और 9 से अधिक है अन्यथा।

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

स्रोत


6

अगर यह सिर्फ यह जानना है कि क्या एक संस्करण दूसरे की तुलना में कम है, तो मैं जाँच कर आया था कि क्या sort --version-sort मेरे संस्करण के क्रम में परिवर्तन हुआ है:

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

5

मैंने एक फ़ंक्शन लागू किया जो डेनिस विलियमसन के समान परिणाम देता है लेकिन कम लाइनों का उपयोग करता है। यह शुरू में एक स्वच्छता जांच करता है जो 1..0उसके परीक्षणों से विफल हो जाता है (जो मैं तर्क देता हूं कि मामला होना चाहिए ) लेकिन उसके सभी अन्य परीक्षण इस कोड के साथ पास होते हैं:

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

यह काम नहीं कर रहा है ... यह सोचता है कि 1.15 1.8.1 से कम है।
कार्लो वुड

5

यहाँ एक सरल बैश फ़ंक्शन है जो बिना किसी बाहरी कमांड का उपयोग करता है। यह उन वर्जन स्ट्रिंग्स के लिए काम करता है, जिनमें तीन से तीन न्यूमेरिक हिस्से होते हैं - 3 से कम भी ठीक है। इसे आसानी से और अधिक के लिए बढ़ाया जा सकता है। यह औजार =, <, <=, >, >=, और !=स्थिति।

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

यहाँ परीक्षण है:

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

परीक्षण आउटपुट का एक सबसेट:

<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
  • फ़ंक्शन V- शुद्ध बैश समाधान, कोई बाहरी उपयोगिताओं की आवश्यकता नहीं है।
  • का समर्थन करता है = == != < <= >और>= (lexicographic)।
  • वैकल्पिक पूंछ पत्र की तुलना: 1.5a < 1.5b
  • असमान लंबाई की तुलना: 1.6 > 1.5b
  • बाएं-से-दाएं पढ़ता है 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
}

कोड समझाया गया

पंक्ति 1 : स्थानीय चर को परिभाषित करें:

  • a, op, b- तुलना ऑपरेंड और ऑपरेटर, यानी, "3.6"> "3.5A"।
  • al, bl- के पत्र पूंछ aऔर b,, पूंछ आइटम पर प्रारंभ यानी, "6" और "5 ए"।

पंक्तियाँ 2, 3 : टेल आइटम से लेफ्ट-ट्रिम अंक तो केवल अक्षर बचे हैं, यदि कोई हो, अर्थात "" और "a"।

पंक्ति 4 : सही ट्रिम पत्र से aऔर bसिर्फ स्थानीय चर के रूप सांख्यिक वस्तुओं के अनुक्रम छोड़ने के लिए aiऔरbi "अर्थात" 3.6 "और" 3.5 "के । उल्लेखनीय उदाहरण: "4.01-RC2"> "4.01-RC1" पैदावार ai = "4.01" al = "- RC2" और bi = "4.01" bl = "- RC1"।

पंक्ति 6 : स्थानीय चर को परिभाषित करें:

  • ap, bp- के लिए शून्य सही-गद्दी aiऔर bi। केवल इंटर-आइटम डॉट्स रखकर प्रारंभ करें, जिनमें से संख्या क्रमशः aऔर के तत्वों की संख्या के बराबर होती bहै।

पंक्ति 7 : फिर प्रत्येक बिंदु के बाद पैडिंग मास्क बनाने के लिए "0" को जोड़ें।

पंक्ति 9 : स्थानीय चर:

  • w - आइटम की चौड़ाई
  • fmt - प्रिंटफ प्रारूप स्ट्रिंग, गणना करने के लिए
  • x - अस्थायी
  • IFS=.बैश के साथ '' पर परिवर्तनशील मानों को विभाजित करता है।

पंक्ति 10 : गणना करें w, अधिकतम आइटम चौड़ाई, जिसका उपयोग लेक्सिकोग्राफ़िक तुलना के लिए आइटम संरेखित करने के लिए किया जाएगा। हमारे उदाहरण में w = 2 है।

रेखा 11 : का हर किरदार की जगह printf संरेखण प्रारूप बनाएं $a.$bसाथ %${w}s, यानी, "3.6"> "3.5A" पैदावार "% 2s% 2s% 2s% 2s"।

पंक्ति 12 : "printf -v" a, चर का मान निर्धारित करता है a। यह a=sprintf(...)कई प्रोग्रामिंग भाषाओं में बराबर है । ध्यान दें कि यहाँ, IFS = के प्रभाव से। printfव्यक्तिगत मदों में विभाजित करने के लिए तर्क ।

रिक्त स्थान के साथ बाएं-पैड वाले पहले printfआइटम aहैं, जबकि पर्याप्त "0" आइटम से bpयह सुनिश्चित करने के लिए जोड़ा जाता है कि परिणामी स्ट्रिंग aसमान रूप से स्वरूपित की तुलना में सार्थक हो सकती है b

ध्यान दें कि हम संलग्न bp- नहीं apकरने के लिए aiक्योंकि apऔर bpविभिन्न lenghts हो सकता है, इसलिए में इस परिणाम aऔर bबराबर लंबाई रही है।

दूसरे के साथ printfहम सार्थक तुलना को सक्षम करने के लिए पर्याप्त पैडिंग के साथ पत्र भाग alको जोड़ते हैं a। अब aतुलना के लिए तैयार है b

पंक्ति १३ : पंक्ति १२ लेकिन उसी के लिए b

पंक्ति 15 : गैर-बिल्ट-इन ( <=और >=) और बिल्ट-इन ऑपरेटरों के बीच विभाजन तुलना के मामले ।

लाइन 16 : यदि तुलना ऑपरेटर है <=तो a<b or a=bक्रमशः - के लिए परीक्षण करें>= a<b or a=b

लाइन 17 : अंतर्निहित तुलना ऑपरेटरों के लिए परीक्षण।

<>

# 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

मैं व्यस्त लिनक्स के साथ एम्बेडेड लिनक्स (योक्टो) का उपयोग कर रहा हूं। बिजीबॉक्सsort में एक -Vविकल्प नहीं होता है (लेकिन बिजीबॉक्सexpr match नियमित अभिव्यक्ति कर सकता है)। तो मुझे एक बैश संस्करण की तुलना की आवश्यकता थी जो उस बाधा के साथ काम करता था।

मैंने "नैसर्गिक प्रकार" एल्गोरिथम के उपयोग की तुलना करने के लिए निम्नलिखित ( डेनिस विलियमसन के उत्तर के समान ) बनाया है। यह स्ट्रिंग को संख्यात्मक भागों और गैर-संख्यात्मक भागों में विभाजित करता है; यह संख्यात्मक भागों की तुलना संख्यात्मक रूप से करता है (इसलिए 10इससे अधिक है 9), और गैर-संख्यात्मक भागों की तुलना सादे ASCII तुलना के रूप में करता है।

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
}

यह अधिक जटिल संस्करण संख्याओं की तुलना कर सकता है जैसे कि

  • 1.2-r3 बनाम 1.2-r4
  • 1.2rc3 बनाम 1.2r4

ध्यान दें कि यह डेनिस विलियमसन के जवाब में कोने-मामलों में से कुछ के लिए एक ही परिणाम नहीं देता है । विशेष रूप से:

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

लेकिन वे कोने के मामले हैं, और मुझे लगता है कि परिणाम अभी भी उचित हैं।


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
जीएनयू सॉर्ट के साथ, आप इस तरह की --check=silentआवश्यकता के बिना, का उपयोग कर सकते हैं test: if printf '%s\n%s' 4.2.0 "$OVFTOOL_VERSION" | sort --version-sort -C
टोबे स्पीट

धन्यवाद @ टोबै स्पाइट
djna

4

यह भी एक pure bashसमाधान है, क्योंकि प्रिंटफ एक बैश बिलिन है।

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//./ }
}

सीमित ... केवल 4 मानों के साथ 100 से कम शुद्ध संख्या के लिए काम करता है। अच्छा प्रयास!
एन्थोनी

2

पुराने संस्करण / व्यस्त बॉक्स के लिए sort । सरल रूप मोटे तौर पर परिणाम प्रदान करता है और अक्सर काम करता है।

sort -n

यह उस संस्करण पर विशेष उपयोगी है जिसमें अल्फा प्रतीक जैसे हैं

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

1

इस बारे में कैसा है? काम करने लगता है?

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

यहाँ किसी भी बाहरी कॉल के बिना एक और शुद्ध बैश समाधान है:

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

और भी सरल उपाय है, यदि आप सुनिश्चित हैं कि प्रश्न के संस्करणों में पहले डॉट के बाद अग्रणी शून्य नहीं है:

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

यह 1.2.3 बनाम 1.3.1 बनाम 0.9.7 की तरह काम करेगा, लेकिन 1.2.3 बनाम 1.2.3.0 या 1.01.1 बनाम 1.1.1 के साथ काम नहीं करेगा।


दूसरा संस्करण परिणाम हो सकता है4.4.4 > 44.3
yairchu

1

यहां शीर्ष उत्तर (डेनिस) का परिशोधन है जो अधिक संक्षिप्त है और एक एकल तुलना के साथ <= और = = को लागू करना आसान बनाने के लिए एक अलग वापसी मूल्य योजना का उपयोग करता है। यह भी पहले चरित्र के बाद [0-9] में नहीं है, सब कुछ तुलनात्मक रूप से तुलना करता है, तो 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
}

यहाँ एक उत्थान है क्योंकि इसका उपयोग यहाँ
कोडब्लिंग

1

मैंने एक और तुलनित्र फ़ंक्शन लागू किया। यह एक दो विशिष्ट आवश्यकताओं के लिए किया था: (i) मैं फ़ंक्शन का उपयोग करके असफल नहीं करना चाहता था return 1, लेकिन echoबजाय; (ii) जैसा कि हम git रिपॉजिटरी संस्करण "1.0" से संस्करणों को प्राप्त कर रहे हैं, "1.0.2" से बड़ा होना चाहिए, जिसका अर्थ है कि "1.0" ट्रंक से आता है।

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
}

टिप्पणी करने और सुधार का सुझाव देने के लिए स्वतंत्र महसूस करें।


1

संस्करण की कमी की जाँच करने के लिए आप संस्करण CLI का उपयोग कर सकते हैं

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

बैश स्क्रिप्ट उदाहरण:

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

मैंने एक अतिरिक्त (और कम और सरल) उत्तर जोड़ने के लिए, इस समस्या को हल किया और हल किया ...

पहला नोट, विस्तारित शेल तुलना विफल रही जैसा कि आप पहले से ही जानते हैं ...

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

संस्करणों और सरल बैश स्ट्रिंग की तुलना करने के लिए '-'- g (या सॉर्ट -V जैसा कि कनक द्वारा उल्लिखित) का उपयोग करके मैंने एक समाधान पाया। इनपुट फ़ाइल में कॉलम 3 और 4 में संस्करण हैं जिनकी मैं तुलना करना चाहता हूं। यह सूची की पहचान मैच के माध्यम से करता है या यदि एक दूसरे से अधिक है। आशा है कि यह अभी भी किसी को भी संभव के रूप में सरल का उपयोग करके ऐसा करने में मदद कर सकता है।

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

इस तरह के विचार के लिए बैरी के ब्लॉग का धन्यवाद ... 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

यह बहुत सरल और छोटा है।


यह जब वहाँ संस्करणों के बैकस्लैश हैं टूट जाएगा, बेहतर की जगह echo -ne "$1\n$2"के साथ printf '%s\n ' "$1" "$2"। इसके अलावा $()बैकटिक्स के बजाय इसका उपयोग करना बेहतर है ।
phk

0

डेनिस के समाधान के लिए धन्यवाद, हम इसे तुलना ऑपरेटरों '>', '<', '=', '==', '<=', और '> =' की अनुमति देने के लिए बढ़ा सकते हैं।

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

हम इसके बाद के भावों में तुलना ऑपरेटरों का उपयोग कर सकते हैं:

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

और केवल सही / गलत परिणाम का परीक्षण करें, जैसे:

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

0

यहां एक और शुद्ध बैश संस्करण है, बल्कि स्वीकृत उत्तर की तुलना में छोटा है। यह केवल यह जांचता है कि क्या कोई संस्करण "न्यूनतम संस्करण" से कम या उसके बराबर है, और यह अल्फ़ान्यूमेरिक अनुक्रमों की जांच करेगा, जो अक्सर गलत परिणाम देता है ("स्नैपशॉट" बाद में "रिलीज़" की तुलना में नहीं है, एक आम उदाहरण देने के लिए) । यह प्रमुख / लघु के लिए ठीक काम करेगा।

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

एक अन्य दृष्टिकोण (@joynes का संशोधित संस्करण) जो बिंदीदार संस्करणों की तुलना प्रश्न में
(यानी "1.2", "2.3.4", "1.0", "1.10.1", आदि) से करता है।
पदों की अधिकतम संख्या पहले से ज्ञात होनी चाहिए। दृष्टिकोण अधिकतम 3 संस्करण स्थिति की उम्मीद करता है।

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

उदाहरण का उपयोग:

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

रिटर्न: 1 के बाद से 1.10.1 1.7 से बड़ा है

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

रिटर्न: 0 1.10.1 के बाद से 1.11 से कम है


0

यहाँ एक शुद्ध बैश समाधान है जो संशोधन का समर्थन करता है (जैसे '1.0-r1'), डेनिस विलियमसन द्वारा पोस्ट किए गए उत्तर के आधार पर। । इसे आसानी से '-RC1' जैसे सामान का समर्थन करने या नियमित अभिव्यक्ति को बदलकर अधिक जटिल स्ट्रिंग से संस्करण निकालने के लिए संशोधित किया जा सकता है।

कार्यान्वयन के बारे में जानकारी के लिए, कृपया इन-कोड टिप्पणियों को देखें और / या शामिल डिबग कोड को सक्षम करें:

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

वाह ... यह एक पुराने प्रश्न की सूची के नीचे है, लेकिन मुझे लगता है कि यह एक बहुत ही सुंदर जवाब है। शेल पैरामीटर विस्तार ( शेल पैरामीटर विस्तार देखें ) का उपयोग करके पहले प्रत्येक डॉट-अलग संस्करण को अपने स्वयं के सरणी में परिवर्तित करें ।

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//./ })

अब दो सरणियों के पास प्राथमिकता क्रम में संख्यात्मक स्ट्रिंग के रूप में संस्करण संख्या है। उपरोक्त समाधान के बहुत सारे आपको वहां से ले जाते हैं, लेकिन यह सभी अवलोकन से प्राप्त होता है कि संस्करण स्ट्रिंग एक मनमाना आधार के साथ पूर्णांक है। हम पहले असमान अंक (जैसे स्ट्रिंग में वर्णों के लिए strcmp करता है) का परीक्षण कर सकते हैं।

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
}

यह एक ऋणात्मक संख्या को प्रतिध्वनित करता है यदि पहला संस्करण दूसरे से कम है, तो एक शून्य यदि वे समान हैं और एक सकारात्मक संख्या है यदि पहला संस्करण अधिक है। कुछ आउटपुट:

$ 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

पतित मामलों की तरह, ".2" या "3.0।" काम न करें (अपरिभाषित परिणाम), और यदि गैर-संख्यात्मक वर्ण '' के बगल में मौजूद हैं। यह विफल हो सकता है (परीक्षण नहीं किया गया है) लेकिन निश्चित रूप से अपरिभाषित होगा। तो इसे सैनिटाइजिंग फंक्शन या वैध फॉर्मेटिंग के लिए उपयुक्त जांच के साथ जोड़ा जाना चाहिए। इसके अलावा, मुझे यकीन है कि कुछ ट्विकिंग के साथ, यह बहुत अधिक अतिरिक्त सामान के बिना अधिक मजबूत बनाया जा सकता है।


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: <

श्रेय @Shellman को जाता है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.