How to compare two strings in dot separated version format in Bash?

前端 未结 29 1340
慢半拍i
慢半拍i 2020-11-22 06:52

Is there any way to compare such strings on bash, e.g.: 2.4.5 and 2.8 and 2.4.5.1?

相关标签:
29条回答
  • 2020-11-22 07:12

    Well if you know the number of fields you can use -k n,n and get a super-simple solution

    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
    
    0 讨论(0)
  • 2020-11-22 07:12

    Here's a refinement of the top answer (Dennis's) that is more concise and uses a different return value scheme to make it easy to implement <= and >= with a single comparison. It also compares everything after the first character not in [0-9.] lexicographically, so 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
    }
    
    0 讨论(0)
  • 2020-11-22 07:13

    How about this? Seems to work?

    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"
    
    0 讨论(0)
  • 2020-11-22 07:13
    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: <
    

    Credit goes to @Shellman

    0 讨论(0)
  • 2020-11-22 07:14

    Another approach(modified version of @joynes) that compares dotted versions as asked in the question
    (i.e "1.2", "2.3.4", "1.0", "1.10.1", etc.).
    The maximum number of positions has to be known in advance. The approach expects max 3 version positions.

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

    example usage:

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

    returns: 1 since 1.10.1 is bigger than 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"
    

    returns: 0 since 1.10.1 is lower than 1.11

    0 讨论(0)
  • 2020-11-22 07:16
    $ 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
    
    0 讨论(0)
提交回复
热议问题