是否有办法在bash上比较这些字符串,例如:2.4.5和2.8和2.4.5.1?


当前回答

这里是另一个没有任何外部调用的纯bash解决方案:

#!/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 vs 1.3.1 vs 0.9.7这样的版本,但不适用于其他版本 1.2.3 vs 1.2.3.0或1.01.1 vs 1.1.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"

当Bash变得太复杂时,就把它输送到python中!

vercomp(){ echo "$1" "$2" | python3 -c "import re, sys; arr = lambda x: list(map(int, re.split('[^0-9]+', x))); x, y = map(arr, sys.stdin.read().split()); exit(not x >= y)"; }

比较两个版本号的例子:

vercomp 2.8 2.4.5 && echo ">=" || echo "<"

这个python一行代码比较左边版本号和右边版本号,如果左边版本号等于或更高,则退出0。它还处理2.4.5rc3这样的版本

分解后,这是可读的代码:

import re, sys

# Convert a version string into a list "2.4.5" -> [2, 4, 5]
arr = lambda x: list(map(int, re.split('[^0-9]+', x)))

# Read the version numbers from stdin and apply the above function to them
x, y = map(arr, sys.stdin.read().split())

# Exit 0 if the left number is greater than the right
exit(not x >= y)

我希望这对某些人有用(使用awk)

  #!/bin/bash

  available_version=1.2.3 # or online version
  this_version=1.2.1

  if [[ "ok" == "$(echo | awk "(${available_version} > ${this_version}) { print \"ok\"; }")" ]]; then
    echo "Notice, new version is available"
  elif [[ "ok" == "$(echo | awk "(${available_version} == ${this_version}) { print \"ok\"; }")" ]]; then
    echo "OK, version is up to date"
  else
    echo "Warning, the current version is ahead of the online version!"
  fi

感谢Dennis的解决方案,我们可以扩展它以允许比较运算符'>','<','=','==','<='和'>='。

# 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

你可以递归地拆分。和下面的算法进行比较,从这里开始。如果版本相同则返回10,如果版本1大于版本2则返回11,否则返回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"