বাশে বিন্দু দ্বারা বিভক্ত সংস্করণ বিন্যাসে দুটি স্ট্রিং কীভাবে তুলনা করবেন?


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
@ কামিলডিজিডজিক: লাইসেন্সের শর্তাদি এই পৃষ্ঠার নীচে এবং (এবং অন্যান্য বেশিরভাগ) বর্ণিত হয়েছে।
পরবর্তী বিজ্ঞপ্তি না দেওয়া পর্যন্ত বিরতি দেওয়া হয়েছে।

4
gnu.org/license/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
@ সালিমানি অ্যাডজাও মৌস্তফা: এটি এমন ধরণের সংস্করণ পরিচালনা করতে ডিজাইন করা হয়নি। আমি এখানে অন্য কোনও উত্তর দেখতে পাচ্ছি না যা সেই তুলনাটি পরিচালনা করতে পারে।
পরবর্তী বিজ্ঞপ্তি না দেওয়া পর্যন্ত বিরতি দেওয়া হয়েছে।

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
সুন্দর সমাধান। ম্যাক ওএসএক্স ব্যবহারকারীদের জন্য, আপনি জিএনইউ কোরিটিলস জিএসোর্ট ব্যবহার করতে পারেন। যে homebrew মাধ্যমে উপলব্ধ রয়েছে: brew install coreutils। তারপরে উপরেরগুলিকে কেবল gsort ব্যবহারের জন্য পরিবর্তন করা উচিত।
জাস্টসি

প্রতিধ্বনি থেকে -e সরিয়ে এটি আমি উবুন্টুতে একটি স্ক্রিপ্টে সুনির্দিষ্টভাবে কাজ করতে পেয়েছি।
হ্যানস আর

2
এম্বেডড লিনাক্স সিস্টেমে যেমন বুসিবক্সের সাথে কাজ করে না , কারণ বুসিবক্সেরsort-V বিকল্প নেই।
ক্রেগ ম্যাককুইন

3
printfপরিবর্তে এটি ব্যবহার করা ভাল echo -e
পিএইচকে

4
জিএনইউতেও 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। তুলনা ফলাফল যদি সত্য $?হয় 0তবে আপনি সরাসরি ifবিবৃতি দেওয়ার পরে এটি ব্যবহার করতে পারেন ।
KrisWebDev 27'16

48

জিএনইউ সাজানোর জন্য এটির একটি বিকল্প রয়েছে:

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.
কনক

2
এটিকে সংখ্যা অনুসারে বাছাই করা ঠিক নয়। আপনাকে প্রথমে কমপক্ষে স্ট্রিংগুলি স্বাভাবিক করতে হবে।
ফ্র্যাঙ্কসি

3
এম্বেডড লিনাক্স সিস্টেমে যেমন বুসিবক্সের সাথে কাজ করে না , কারণ বুসিবক্সেরsort-V বিকল্প নেই।
ক্রেগ ম্যাককুইন

এটি লক্ষণীয় যে সংস্করণ নম্বরটি যদি কিছু হতে পারে তবে ফর্মটিতে এটি ব্যবহার করা ভাল printf '%s\n' "2.4.5" "2.8" "2.4.5.1" | sort -V
phk

অন্য উত্তরে উল্লিখিত হিসাবে , এটি কেবল সাথে কাজ করে coreutils 7+
ivan_pozdeev

35

ভাল আপনি যদি ক্ষেত্রের সংখ্যা জানেন তবে আপনি -kn, 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
পার্টিতে চার বছর দেরীতে, তবে আমার প্রিয় সমাধানটি এতদূর :)
এলওএএস

হ্যাঁ, -tবিকল্পটি কেবলমাত্র একক চরিত্রের ট্যাব গ্রহণ করে ... অন্যথায়, 2.4-r9পাশাপাশি কাজ করবে। কী লজ্জাজনক: /
স্কটিসিস

1
সোলারিস কম্প্যাটের জন্য আমাকে পরিবর্তন -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)
উপরেরটি এটির

2
এটি সমস্ত ব্যাশের সমস্ত সংস্করণে প্রযোজ্য কিনা তা নিশ্চিত নন, তবে আমার ক্ষেত্রে শেষ রাউন্ড বন্ধনীটির পরে একটি সেমিকোলন অনুপস্থিত।
হোলার ব্র্যান্ডেল

1
@robinst head -nকাজ করার জন্য, আমাকে পরিবর্তন করতে হয়েছিলtr '.' '\n'
ভিক্টর সার্জিয়েনকো

সেমিকোলন যুক্ত হয়েছে।
কোডফোরস্টার

1
@ ওলেকশিচেকুলিয়েভ পাইপ 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, সংস্করণ 1 যদি 2 সংস্করণ 2 এবং 9 অন্যথায় 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 - খাঁটি বাশ সমাধান, কোনও বাহ্যিক উপযোগ প্রয়োজন।
  • সমর্থন = == != < <= >এবং>= (অভিধান)
  • Tailচ্ছিক লেজ অক্ষরের তুলনা: 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- তুলনা operands এবং অপারেটর, অর্থাত্, "3.6"> "3.5a"।
  • al, bl- লেজ লেজগুলির লেজ লেজ aএবং b, প্রাথমিকভাবে, "6" এবং "5 এ" এর আরম্ভ করা হয়েছিল।

লাইন 2, 3 : লেজ আইটেমগুলি থেকে বাম-ছাঁটাই অঙ্কগুলি তাই কেবলমাত্র অক্ষরগুলি থাকে, যদি কোনও হয়, যেমন, "" এবং "ক"।

লাইন 4 : ডান ট্রিম চিঠি থেকে aএবং bমাত্র স্থানীয় ভেরিয়েবল যেমন সাংখ্যিক আইটেম ক্রম ত্যাগ করার aiএবংbi , অর্থাত্, "3.6" এবং "3.5"। উল্লেখযোগ্য উদাহরণ: "4.01-আরসি 2"> "4.01-আরসি 1" ফলন করে আইআই = "4.01" আল = "- আরসি 2" এবং দ্বি = "4.01" ব্লু "" - আরসি 1 "।

লাইন 6 : স্থানীয় ভেরিয়েবলগুলি সংজ্ঞায়িত করুন:

  • ap, bp- জন্য শূন্য ডান-paddings aiএবং bi। শুধুমাত্র আন্ত আইটেমটি বিন্দু, যার সংখ্যা উপাদানের সংখ্যা সমান রেখে শুরু aএবং bযথাক্রমে।

লাইন :: প্যাডিং মাস্কগুলি তৈরি করতে প্রতিটি বিন্দুর পরে "0" যুক্ত করুন।

লাইন 9 : স্থানীয় ভেরিয়েবল:

  • w - আইটেম প্রস্থ
  • fmt - মুদ্রণ ফর্ম্যাট স্ট্রিং, গণনা করা
  • x - অস্থায়ী
  • IFS=.বাশ '' এ পরিবর্তিত ভেরিয়েবলের সাথে ।

লাইন 10 : গণনা করুন w, সর্বাধিক আইটেম প্রস্থ, যা অভিধান সংক্রান্ত তুলনার জন্য আইটেমগুলিকে সারিবদ্ধ করতে ব্যবহৃত হবে। আমাদের উদাহরণে ডাব্লু = 2।

লাইন 11 : প্রতিটি অক্ষর , অর্থাৎ "3.6"> "3.5a" "% 2s% 2s% 2s% 2s" এর $a.$bসাথে প্রতিস্থাপন করে %${w}sপ্রিন্টফ প্রান্তিককরণ বিন্যাস তৈরি করুন ।

লাইন 12 : "printf -v a" ভেরিয়েবলের মান নির্ধারণ করে a। এটি a=sprintf(...)অনেক প্রোগ্রামিং ভাষায় সমান । নোট করুন যে এখানে, আইএফএস = এর প্রভাব দ্বারা। যুক্তি printfপৃথক আইটেম বিভক্ত।

প্রথম printfআইটেমগুলিতে aফাঁক দিয়ে বাম-প্যাডযুক্ত রয়েছে যখন bpফলস্বরূপ স্ট্রিংটি aঅনুরূপভাবে ফর্ম্যাটের সাথে তুলনামূলকভাবে তুলনামূলকভাবে করা যায় তা নিশ্চিত করার জন্য পর্যাপ্ত আইটেমগুলি সংযুক্ত করা হয় whileb

মনে রাখবেন আমরা যোগ bp- না apকরার aiকারণ apএবং bpবিভিন্ন lenghts থাকতে পারে, তাই এই ফলাফল aএবং bসমান লেন্থ হচ্ছে।

দ্বিতীয় সঙ্গে printfআমরা চিঠি অংশ যোগ alকরতে aঅর্থপূর্ণ তুলনা সক্ষম করতে যথেষ্ট প্যাডিং সঙ্গে। এখন aতুলনা করার জন্য প্রস্তুত b

লাইন 13 : লাইন 12 হিসাবে একই কিন্তু b

লাইন 15 : অ-অন্তর্নির্মিত ( <=এবং >=) এবং অন্তর্নির্মিত অপারেটরগুলির মধ্যে বিভাজক তুলনা কেস ।

লাইন 16 : যদি তুলনা অপারেটরটি হয় যথাক্রমে - এর <=জন্য পরীক্ষা করা a<b or a=bহয়>= a<b or a=b

লাইন 17 : বিল্ট-ইন তুলনা অপারেটরগুলির জন্য পরীক্ষা Test

<>

# 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
টবি স্পাইট 10 ই

আপনাকে ধন্যবাদ @ টবি স্পিড
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
ইয়ারছু

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
}

এখানে একটি upvote কারণ এটি এখানে
কোডব্লিং

1

আমি আর একটি তুলনামূলক ফাংশন প্রয়োগ করেছি। এর একটির দুটি নির্দিষ্ট প্রয়োজনীয়তা ছিল: (i) আমি চাইনি return 1বরং ব্যবহারের মাধ্যমে ফাংশনটি ব্যর্থ হয় echo; (ii) যেহেতু আমরা গিট সংগ্রহস্থল সংস্করণ "1.0" থেকে সংস্করণগুলি পুনরুদ্ধার করছি "1.0" "এর চেয়ে বড় হওয়া উচিত, যার অর্থ" 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

সংস্করণের সীমাবদ্ধতাগুলি পরীক্ষা করতে আপনি সংস্করণ সংস্করণ ব্যবহার করতে পারেন

$ 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

সংস্করণ এবং সরল বাশ স্ট্রিং তুলনাটি অর্ডার করতে বাছাই -t '.'- g (বা কনক দ্বারা উল্লিখিত বাছাই-ভি) ব্যবহার করে আমি একটি সমাধান পেয়েছি। ইনপুট ফাইলটিতে 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

বাছাই করা ধারণার জন্য ব্লগকে ধন্যবাদ ... রেফ: http://bkhome.org/blog/?view বিস্তারিত বিবরণ=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"। এছাড়াও $()ব্যাকটিক্সের পরিবর্তে ব্যবহার করা ভাল ।
পিএইচকে

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

এখানে আর একটি খাঁটি বাশ সংস্করণ গ্রহণযোগ্য উত্তরের চেয়ে ছোট rather এটি কেবলমাত্র কোনও সংস্করণ "ন্যূনতম সংস্করণ" এর চেয়ে কম বা সমান কিনা তা যাচাই করে এবং এটি বর্ণানুক্রমিকভাবে বর্ণানুক্রমিক অনুক্রমগুলি পরীক্ষা করে দেখায় যা প্রায়শই ভুল ফলাফল দেয় (একটি সাধারণ উদাহরণ দেওয়ার জন্য "স্ন্যাপশট" "রিলিজ" এর পরে নয়) । এটি মেজর / অপ্রাপ্তবয়স্কদের জন্য ভাল কাজ করবে।

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

আরেকটি পদ্ধতির (@ জয়েনিসের পরিবর্তিত সংস্করণ) যা প্রশ্নে জিজ্ঞাসা করা বিন্দু সংস্করণগুলির তুলনা করে
(যেমন "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 এর চেয়ে বড়

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

এখন দুটি অ্যারে সংখ্যার স্ট্রিং হিসাবে অগ্রাধিকার ক্রমে সংস্করণ নম্বর রয়েছে। উপরের প্রচুর সমাধানগুলি আপনাকে সেখান থেকে নিয়ে যায়, তবে এটি সমস্ত পর্যবেক্ষণ থেকে প্রাপ্ত যে সংস্করণটির স্ট্রিং একটি স্বেচ্ছাচারিত বেসের সাথে কেবল একটি পূর্ণসংখ্যা। আমরা প্রথম অসম সংখ্যা (যেমন স্ট্রিংয়ের অক্ষরের জন্য স্ট্রিম্পের মতো করে) সন্ধান করতে পারি।

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

ক্রেডিট @ শেলম্যানের কাছে যায়

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.