有什么方法可以在bash上比较此类字符串,例如:2.4.52.82.4.5.1吗?

评论

不,请不要使用BC。它是文字而不是数字。 2.1 <2.10会以这种方式失败。

#1 楼

这是一个纯Bash版本,不需要任何外部公用程序:

#!/bin/bash
vercomp () {
    if [[  ==  ]]
    then
        return 0
    fi
    local IFS=.
    local i ver1=() ver2=()
    # 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  
    case $? in
        0) op='=';;
        1) op='>';;
        2) op='<';;
    esac
    if [[ $op !=  ]]
    then
        echo "FAIL: Expected '', Actual '$op', Arg1 '', Arg2 ''"
    else
        echo "Pass: ' $op '"
    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'


评论


您能否明确声明此代码段的许可?代码看起来很完美,但是我不确定是否可以在AGPLv3许可的项目中使用它。

–卡米尔(Kamil Dziedzic)
14年7月31日在23:31

@KamilDziedzic:许可条款在本页底部(以及大多数其他条款)中列出。

–丹尼斯·威廉姆森
2014年8月1日在1:08

gnu.org/licenses/license-list.html#ccbysa请不要将其用于软件或文档,因为它与GNU GPL不兼容:/,但+1表示出色的代码

–卡米尔(Kamil Dziedzic)
2014年8月1日在9:44

这将失败'1.4rc2> 1.3.3'。注意字母数字版本

– Salimane Adjao Moustapha
2014年12月9日在11:52

@SalimaneAdjaoMoustapha:并非旨在处理这种类型的版本字符串。我在这里看不到任何其他可以处理这种比较的答案。

–丹尼斯·威廉姆森
2014年12月9日12:45

#2 楼

如果您具有coreutils-7(在Ubuntu Karmic中但在Jaunty中没有),则您的sort命令应具有一个-V选项(版本排序),您可以用来进行比较:

verlte() {
    [  "" = "`echo -e "\n" | sort -V | head -n1`" ]
}

verlt() {
    [ "" = "" ] && return 1 || verlte  
}

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


评论


不错的解决方案。对于Mac OSX用户,可以使用GNU Coreutils gsort。可以通过自制软件获得:brew install coreutils。然后只需修改以上内容即可使用gsort。

–justsee
2013年4月1日下午4:33

我通过在echo中删除-e使其在Ubuntu脚本中工作。

–汉斯·R。
2014年3月31日在12:38

不适用于例如嵌入式Linux系统上的Busybox,因为Busybox排序没有-V选项。

–克雷格·麦昆(Craig McQueen)
2015年7月1日4:47



最好使用printf而不是echo -e。

–phk
16年11月5日,10:53

GNU sort也具有-C或--check = silent,因此您可以编写verlte(){printf'%s \ n%s'“ $ 1”“ $ 2” |排序-C -V};并严格检查小于,而不是更简单地通过verlt(){! verlte“ $ 2”“ $ 1”}。

– Toby Speight
18-10-19在10:27

#3 楼

可能没有普遍正确的方法来实现这一目标。如果您要比较Debian软件包系统中的版本,请尝试dpkg --compare-versions <first> <relation> <second>.

评论


用法:dpkg --compare-versions“ 1.0”“ lt”“ 1.2”表示1.0小于1.2。比较结果$?如果为true,则为0,因此您可以在if语句后直接使用它。

– KrisWebDev
16 Mar 27 '16 at 15:32

#4 楼

GNU排序有一个选项:

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



2.4.5
2.4.5.1
2.8


评论


问题似乎与版本排序有关。考虑:echo -e“ 2.4.10 \ n2.4.9” |排序-n -t。

– kanaka
2010-10-26 13:46



用数字对它进行排序是不正确的。您至少需要首先规范化字符串。

– Frankc
10-10-26在19:44

不适用于例如嵌入式Linux系统上的Busybox,因为Busybox排序没有-V选项。

–克雷格·麦昆(Craig McQueen)
2015年7月1日在4:59

值得注意的是,如果版本号可以是任何数字,则最好以printf'%s \ n'“ 2.4.5”“ 2.8”“ 2.4.5.1” |排序-V。

–phk
16-11-5在10:58

如另一个答案所述,这仅适用于coreutils 7+。

– ivan_pozdeev
17年12月24日在8:30

#5 楼

好吧,如果您知道字段数,则可以使用-k 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


评论


晚了四年,但是到目前为止,我最喜欢的解决方法是:)

– LOAD
15年3月11日在8:15

是的,-t选项仅接受单个字符制表符...否则,2.4-r9也可以使用。多可惜 :/

–scottysseus
15年7月7日在14:53

对于Solaris兼容,我必须将-g更改为-n。有什么原因不适合这个例子?在旁注中...要执行“大于”类型比较,您可以检查所需的排序是否与实际排序相同。 wanted =“ 1.9 \ n1.11”; actual =“ $(echo -e $ desired | sort -t'。'-k 1,1 -k 2,2 -g)”;然后验证[[$ desired] =“ $ actual”]。

– Tresf
16年1月16日在6:16



#6 楼

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


使用方法:

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


(来自https://apple.stackexchange.com/a/123408/11374)

评论


这比仅使用上面建议的默认bash printf优越得多。它会正确处理常规printf无法处理的版本,例如“ 1.09”,因为“ 09不是正确的数字”。它还会自动删除前导零,这很有用,因为有时前导零会导致比较错误。

– Oleksii Chekulaiev
17-10-30在20:15



#7 楼

此版本中最多用于4个字段。

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


评论


如果版本也可以包含5个字段,则可以使上述内容安全,例如:printf“%03d%03d%03d%03d” $(echo“ $ 1” | tr'。''\ n'| head -n 4 )

–robinst
15年4月20日在4:57

不知道这是否适用于所有版本的bash,但在我的情况下,最后一个圆括号后缺少分号。

–霍尔格·布兰德尔(Holger Brandl)
17年8月11日在17:26

@robinst要使-n正常工作,我必须更改为tr'。 '\ n'

– Victor Sergienko
17-10-13在21:04

添加了分号。

– codeforester
18-2-26在23:22

@OleksiiChekulaiev通过sed的s / \(^ \ | \)0 \([0-9] [0-9] * \)/ \ 1 \ 2 / g'输出管道tr可以解决这个问题(相当笨拙)

–奥修斯
18年6月13日在17:32

#8 楼

您可以在.上递归拆分并进行比较,如以下算法所示(从此处获取)。如果版本相同,则返回10,如果版本1大于版本2,则返回11,否则返回9。

#!/bin/bash
do_version_check() {

   [ "" == "" ] && return 10

   ver1front=`echo  | cut -d "." -f -1`
   ver1back=`echo  | cut -d "." -f 2-`

   ver2front=`echo  | cut -d "." -f -1`
   ver2back=`echo  | cut -d "." -f 2-`

   if [ "$ver1front" != "" ] || [ "$ver2front" != "" ]; then
       [ "$ver1front" -gt "$ver2front" ] && return 11
       [ "$ver1front" -lt "$ver2front" ] && return 9

       [ "$ver1front" == "" ] || [ -z "$ver1back" ] && ver1back=0
       [ "$ver2front" == "" ] || [ -z "$ver2back" ] && ver2back=0
       do_version_check "$ver1back" "$ver2back"
       return $?
   else
           [ "" -gt "" ] && return 11 || return 9
   fi
}    

do_version_check "" ""




#9 楼

如果只是想知道一个版本是否低于另一个版本,我会检查sort --version-sort是否更改了我的版本字符串的顺序:

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


#10 楼

这是一个简单的Bash函数,不使用任何外部命令。它适用于其中最多包含三个数字部分的版本字符串-小于3也可以。它可以轻松扩展更多。它实现=<<=>>=!=条件。

#!/bin/bash
vercmp() {
    version1= version2= condition=

    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


#11 楼

我实现了一个函数,该函数返回与Dennis Williamson相同的结果,但使用的行数更少。它最初会执行健全性检查,从而导致1..0的测试失败(我认为应该是这种情况),但是他的所有其他测试均通过以下代码通过:

#!/bin/bash
version_compare() {
    if [[  =~ ^([0-9]+\.?)+$ &&  =~ ^([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。

–卡洛·伍德(Carlo Wood)
17年1月28日在23:47



#12 楼


功能V-纯bash解决方案,无需外部实用程序。
支持= == != < <= >>=(字典)。
可选的尾字母比较: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() # -a -op -$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= op= b= 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行:定义局部变量:




aopb-比较操作数和运算符,即“ 3.6”>“ 3.5a”。

albl-ab的字母尾部被初始化为尾项,即,“ 6”和“ 5a”。

第2行,第3行:末尾项的左修饰数字,因此仅保留字母(如果有),即“”和“ a”。

第4行:从ab右对齐字母,仅保留数字项序列作为局部变量ai d bi,即“ 3.6”和“ 3.5”。
值得注意的示例:“ 4.01-RC2”>“ 4.01-RC1”产生ai =“ 4.01” al =“-RC2”和bi =“ 4.01” bl =“-RC1”。

第6行:定义局部变量:



apbp-aibi的右填充为零。首先仅保留项目间的点,其点数分别等于ab的元素数。

第7行:然后在每个点后添加“ 0”以制作填充蒙版。

第9行:局部变量:



w-项目宽度

fmt-要计算的printf格式字符串

x-临时
bash使用IFS=.将变量值分割为'。'。

第10行:计算最大项目宽度w,该宽度将用于对齐词典比较的项目。在我们的示例中,w = 2。

第11行:通过将$a.$b的每个字符替换为%${w}s来创建printf对齐格式,即,“ 3.6”>“ 3.5a”产生“%2s%2s%2s%2s”。

第12行:“ printf -v a”设置变量a的值。在许多编程语言中,这等效于a=sprintf(...)。请注意,此处受IFS =的影响。 printf的参数分为多个单独的项目。

第一个printf的项目在a的左边填充空格,而bp附加了足够的“ 0”项目,以确保生成的字符串a有意义与类似格式的b相比。

请注意,我们将bp附加到ap而不是ai,因为apbp的长度可能不同,因此这导致ab的长度相等。 br />对于第二个printf,我们在字母al后面附加字母部分a,并添加足够的填充以进行有意义的比较。现在a已准备好与b进行比较。

第13行:与第12行相同,但对于b

第15行:在非内置(<=第16行:如果比较运算符为>=,则分别测试<=-请分别测试a<b or a=b>=

第17行:测试内置函数比较运算符。

<>

# All tests

function P { printf "$@"; }
function EXPECT { printf "$@"; }
function CODE { awk $BASH_LINENO'==NR{print " ",,}' "q4312078q"; }
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


#13 楼

这也是一个pure bash解决方案,因为printf是内置的bash。

function ver()
# Description: use for comparisons of version strings.
#   : 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//./ }
}


评论


受限...仅适用于小于100且具有正好4个值的纯数字。不错的尝试!

–安东尼
6月1日下午3:11

我喜欢这一点,但您可以避免%02s出现“无效数字”错误,并为更大的值填入更多内容;我去了一个不纯的变体,将其扩展到字母(在数字之前排序):alpha = a,beta = b,前缀a-z和','在0-9之前排序; [-。]分隔符; 0填充:本地v = $(echo“ $ 1” | sed -Ee's / alpha / a / g; s / beta / b / g; s /([[az] +)/,\ 1 / g; s / -/。/G;'); printf“%09s%09s%09s%09s%09s%09s%09s” $ {v //./}

–bazzargh
11月3日,18:29



#14 楼

我正在使用带有BusyBox的嵌入式Linux(Yocto)。 BusyBox sort没有-V选项(但是BusyBox expr match可以执行正则表达式)。因此,我需要一个可以处理该约束的Bash版本比较。

我使用“自然排序”类型的算法进行了以下比较(类似于Dennis Williamson的回答)。它将字符串分为数字部分和非数字部分;它以数字方式比较数字部分(因此10大于9),并将非数字部分作为普通ASCII比较进行比较。

ascii_frag() {
    expr match "" "\([^[:digit:]]*\)"
}

ascii_remainder() {
    expr match "" "[^[:digit:]]*\(.*\)"
}

numeric_frag() {
    expr match "" "\([[:digit:]]*\)"
}

numeric_remainder() {
    expr match "" "[[:digit:]]*\(.*\)"
}

vercomp_debug() {
    OUT=""
    #echo "${OUT}"
}

# return 1 for  > 
# return 2 for  < 
# return 0 for equal
vercomp() {
    local WORK1=""
    local WORK2=""
    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
}


它可以比较更复杂版本号,如



请注意,对于丹尼斯·威廉姆森(Dennis Williamson)的答案中的某些极端情况,它不会返回相同的结果。特别是:

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


但是这些都是极端的情况,我认为结果仍然合理。

#15 楼

$ 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


评论


使用GNU排序,可以使用--check = silent,而无需进行测试,例如:if printf'%s \ n%s'4.2.0“ $ OVFTOOL_VERSION” |排序--version-sort -C

– Toby Speight
18-10-19在10:11

谢谢@Toby Speight

– djna
2月12日8:44

#16 楼

对于旧版本/ busybox sort。简单的形式可以提供大致的结果,并且经常可以使用。

sort -n


这在包含字母符号的版本中特别有用,例如

#17 楼

这个怎么样?似乎可以工作?

checkVersion() {
subVer1=
subVer2=

[ "$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=
ver2=
checkVersion "$ver1" "$ver2"


#18 楼

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

#!/bin/bash

function version_compare {

IFS='.' read -ra ver1 <<< ""
IFS='.' read -ra ver2 <<< ""

[[ ${#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 " $(version_compare "" "") "


还有一个更简单的解决方案,如果您确定所涉及的版本不包含前导零。在第一个点之后:

#!/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 " $(version_compare "" "") "


这将适用于1.2.3 vs 1.3.1 vs 0.9.7,但不适用于
1.2.3和1.2.3.0或1.01.1和1.1.1

评论


第二版可能会导致4.4.4> 44.3

–yairchu
16年6月21日在8:31

#19 楼

这是对最佳答案(丹尼斯)的改进,该答案更加简洁,并使用不同的返回值方案来简化一次比较即可实现<=和> =的情况。它还按字典顺序比较了[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 [[  ==  ]]; 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
}


评论


这是赞誉,因为它在这里被使用

–代码
18年2月13日在16:11

#20 楼

我实现了另一个比较器功能。这有两个特定要求:(i)我不希望通过使用return 1来使函数失败,而是希望使用echo来使函数失败; (ii)由于我们正在从git存储库中检索版本,因此“ 1.0”应大于“ 1.0.2”,这意味着“ 1.0”来自主干。

br />随时发表评论并提出改进建议。

#21 楼

您可以使用版本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


#22 楼

我碰到并解决了这个问题,添加了一个额外的(并且更短和更简单的)答案... br />
    if [[ 1.2.0 < 1.12.12 ]]; then echo true; else echo false; fi
    false


使用sort -t'.'- g(或kanaka提到的sort -V)订购版本和简单的bash字符串比较,我找到了解决方案。输入文件包含我要比较的第3列和第4列中的版本。这会遍历列表,以标识一个匹配项,或者一个大于另一个。希望这仍然可以帮助希望使用bash做到这一点的人尽可能地简单。 :http://bkhome.org/blog/?viewDetailed=02199

#23 楼

### the answer is does we second argument is higher
function _ver_higher {
        ver=`echo -ne "\n" |sort -Vr |head -n1`
        if [ "" == "" ]; then
                return 1
        elif [ "" == "$ver" ]; then
                return 0
        else
                return 1
        fi
}

if _ver_higher  ; then
        echo higher
else
        echo same or less
fi


非常简单小巧。

评论


当版本中存在反斜杠时,它将中断,最好将echo -ne“ $ 1 \ n $ 2”替换为printf'%s \ n'“ $ 1”“ $ 2”。另外,最好使用$()而不是backtics。

–phk
16-11-5在10:52



#24 楼

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

# compver ver1 '=|==|>|<|>=|<=' ver2
compver() { 
    local op
    vercomp  
    case $? in
        0) op='=';;
        1) op='>';;
        2) op='<';;
    esac
    [[  == *$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


#25 楼

这是另一个纯bash版本,比接受的答案小。它仅检查版本是否小于或等于“最低版本”,并且将按字典顺序检查字母数字序列,这通常会得出错误的结果(举一个常见的例子,“快照”不晚于“发行版”) 。

is_number() {
    case "$BASH_VERSION" in
        3.1.*)
            PATTERN='\^\[0-9\]+$'
            ;;
        *)
            PATTERN='^[0-9]+$'
            ;;
    esac

    [[ "" =~ $PATTERN ]]
}

min_version() {
    if [[ $# != 2 ]]
    then
        echo "Usage: min_version current minimum"
        return
    fi

    A="${1%%.*}"
    B="${2%%.*}"

    if [[ "$A" != "" && "$B" != "" && "$A" == "$B" ]]
    then
        min_version "${1#*.}" "${2#*.}"
    else
        if is_number "$A" && is_number "$B"
        then
            [[ "$A" -ge "$B" ]]
        else
            [[ ! "$A" < "$B" ]]
        fi
    fi
}

可以正常工作。

#26 楼

另一种方法(@joynes的修改版本),按照问题中的要求比较虚线版本(即“ 1.2”,“ 2.3.4”,“ 1.0”,“ 1.10.1”等)。
必须事先知道最大职位数。该方法预期最多3个版本位置。

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


示例用法:

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

#27 楼

这是一个纯粹的Bash解决方案,它根据Dennis Williamson发布的答案支持修订(例如'1.0-r1')。可以轻松地对其进行修改以支持“ -RC1”之类的东西,也可以通过更改正则表达式从更复杂的字符串中提取版本。

有关实现的详细信息,请参阅代码中的注释和/或启用随附的调试代码:

#!/bin/bash

# Compare two version strings [: version string 1 (v1), : 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
    [[ "" == "" ]] && 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 [[ "" =~ ${regex} ]]; then
        va1=(${BASH_REMATCH[1]})
        [[ -n "${BASH_REMATCH[2]}" ]] && vr1=${BASH_REMATCH[2]}
    else
        va1=()
    fi
    if [[ "" =~ ${regex} ]]; then
        va2=(${BASH_REMATCH[1]})
        [[ -n "${BASH_REMATCH[2]}" ]] && vr2=${BASH_REMATCH[2]}
    else
        va2=()
    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 [: version string 1, : version string 2, : expected result]
function test_compare_versions() {
    local op
    compare_versions "" ""
    case $? in
        0) op="==" ;;
        1) op=">" ;;
        2) op="<" ;;
    esac
    if [[ "$op" == "" ]]; then
        echo -e "\e[1;32mPASS: ' $op '\e[0m"
    else
        echo -e "\e[1;31mFAIL: '  ' (result: ' $op ')\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"


#28 楼

哇...这是一个老问题了,但是我认为这是一个非常优雅的答案。首先,使用shell参数扩展(请参阅Shell参数扩展)将每个点分隔的版本转换为其自己的数组。

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”。不起作用(不确定的结果),并且如果在'。'旁出现非数字字符。它可能会失败(未经测试),但肯定是不确定的。因此,应将其与消毒功能或有效格式的适当检查配合使用。另外,我敢肯定,通过一些调整,可以在不增加额外负担的情况下使其变得更健壮。

#29 楼

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 "" ] || [ -z "" ]; then
    echo "=" && exit 0
  fi
  local v1=`echo -e "" | tr -d '[[:space:]]'`
  local v2=`echo -e "" | 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

#30 楼

我不喜欢这些解决方案中的任何一个,因为它们有故障,无法携带等。复制/粘贴在此处...
源:
##
# Compare two versions.
#
# **Usage:** version_compare version1 operator version2
#
# - operator:
#
#   + ``lesser_than``, ``-lt``, ``<``
#   + ``lesser_than_or_equal``, ``-le``, ``<=``
#   + ``greater_than``, ``-gt``, ``>``
#   + ``greater_than_or_equal``, ``-ge``, ``>=``
#   + ``equal``, ``-eq``, ``==``
#   + ``not_equal``, ``-ne``, ``!=``
#
# - version{1,2}: arbitrary version strings to compare
#
# **Version Format:** ``[0-9]+($VERSION_SEPARATOR[0-9]+)*`` (i.e. 1, 1.0, 90, 1.2.3.4)
#
# **Returns:** true if comparison statement is correct
##
version_compare() {
    _largest_version "" ""; _cmp="$(printf '%s' "$?")"

    # Check for valid responses or bail early
    case "$_cmp" in
        1|0|2) :;;
        *) _die "$_cmp" 'version comparison failed';;
    esac

    # The easy part
    case "" in
        'lesser_than'|'-lt'|'<')
            [ "$_cmp" = '2' ] && return 0
            ;;
        'lesser_or_equal'|'-le'|'<=')
            [ "$_cmp" = '0' ] && return 0
            [ "$_cmp" = '2' ] && return 0
            ;;
        'greater_than'|'-gt'|'>')
            [ "$_cmp" = '1' ] && return 0
            ;;
        'greater_or_equal'|'-ge'|'>=')
            [ "$_cmp" = '1' ] && return 0
            [ "$_cmp" = '0' ] && return 0
            ;;
        'equal'|'-eq'|'==')
            [ "$_cmp" = '0' ] && return 0
            ;;
        'not_equal'|'-ne'|'!=')
            [ "$_cmp" = '1' ] && return 0
            [ "$_cmp" = '2' ] && return 0
            ;;
        *) _die 7 'Unknown operatoration called for version_compare().';;
    esac
    return 1
}

##
# Print a formatted (critical) message and exit with status.
#
# **Usage:** _die [exit_status] message
#
# - exit_status: exit code to use with script termination (default: 1)
# - message: message to print before terminating script execution
##
_die() {
        # If first argument was an integer, use as exit_status
        if [ "" -eq "" ] 2>/dev/null; then
                _exit_status=""; shift
        else
                _exit_status=1
        fi

        printf '*** CRITICAL: %s ***\n' ""
        exit "$_exit_status"
}

##
# Compare two versions.
# Check if one version is larger/smaller/equal than/to another.
#
# **Usage:** _largest_version ver1 ver2
#
# Returns: ( > ): 1 ; ( = ): 0 ; ( < ): 2
# [IOW- 1 =  is largest; 0 = neither ; 2 =  is largest]
##
_largest_version() (
    # Value used to separate version components
    VERSION_SEPARATOR="${VERSION_SEPARATOR:-.}"

    for _p in "" ""; do
        [ "$(printf %.1s "$_p")" = "$VERSION_SEPARATOR" ] &&
            _die 7 'invalid version pattern provided'
    done

    # Split versions on VER_SEP into int/sub
    _v=""
    _v1=""
    _s1="${1#*$VERSION_SEPARATOR}"
    if [ "$_v1" = "$_s1" ]; then
        _s1=''
        _m1="$_v1"
    else
        _m1="${1%%$VERSION_SEPARATOR*}"
    fi
    _v2=""
    _s2="${2#*$VERSION_SEPARATOR}"
    if [ "$_v2" = "$_s2" ]; then
        _s2=''
        _m2="$_v2"
    else
        _m2="${2%%$VERSION_SEPARATOR*}"
    fi

    # Both are equal
    [ "$_v1" = "$_v2" ] && return 0

    # Something is larger than nothing (30 < 30.0)
    if [ -n "$_v1" ] && [ ! -n "$_v2" ]; then
        return 1
    elif [ ! -n "$_v1" ] && [ -n "$_v2" ]; then
        return 2
    fi

    # Check for invalid
    case "$_m1$_m2" in
        *[!0-9]*)
            _die 7 'version_compare called with unsupported version type'
            ;;
    esac

    # If a ver_sep is present
    if [ "${_v#*$VERSION_SEPARATOR}" != "$_v" ]; then
        # Check for a larger "major" version number
        [ "$_m1" -lt "$_m2" ] && return 2
        [ "$_m1" -gt "$_m2" ] && return 1

        # Compare substring components
        _largest_version "$_s1" "$_s2"; return "$?"
    else
        # Only integers present; simple integer comparison
        [ "$_v1" -lt "$_v2" ] && return 2
        [ "$_v1" -gt "$_v2" ] && return 1
    fi
)

测试:
# Simple test of all operators
( version_compare '1' 'lesser_than' '2' ); [ "$?" = '0' ] || return 1
( version_compare '2' 'equal' '2' ); [ "$?" = '0' ] || return 1
( version_compare '3' 'not_equal' '1' ); [ "$?" = '0' ] || return 1
( version_compare '2' 'greater_than' '1' ); [ "$?" = '0' ] || return 1
( version_compare '1' '-lt' '2' ); [ "$?" = '0' ] || return 1
( version_compare '2' '-eq' '2' ); [ "$?" = '0' ] || return 1
( version_compare '3' '-ne' '1' ); [ "$?" = '0' ] || return 1
( version_compare '2' '-gt' '1' ); [ "$?" = '0' ] || return 1

# Semver test of primary operators (expect true)
( version_compare '7.0.1' '-lt' '7.0.2' ); [ "$?" = '0' ] || return 1
( version_compare '7.0.2' '-eq' '7.0.2' ); [ "$?" = '0' ] || return 1
( version_compare '3.0.2' '-ne' '2.0.7' ); [ "$?" = '0' ] || return 1
( version_compare '7.0.2' '-gt' '7.0.1' ); [ "$?" = '0' ] || return 1

# Semver test of primary operators (expect false)
( version_compare '7.0.2' '-lt' '7.0.1' ); [ "$?" = '1' ] || return 1
( version_compare '3.0.2' '-eq' '2.0.7' ); [ "$?" = '1' ] || return 1
( version_compare '7.0.2' '-ne' '7.0.2' ); [ "$?" = '1' ] || return 1
( version_compare '7.0.1' '-gt' '7.0.2' ); [ "$?" = '1' ] || return 1

# Mismatched version strings (expect true)
( version_compare '7' '-lt' '7.1' ); [ "$?" = '0' ] || return 1
( version_compare '3' '-ne' '7.0.0' ); [ "$?" = '0' ] || return 1
( version_compare '7.0.1' '-gt' '7' ); [ "$?" = '0' ] || return 1

# Mismatched version strings (expect false)
( version_compare '7.0.0' '-eq' '7.0' ); [ "$?" = '1' ] || return 1

# Invalid operation supplied
( version_compare '2' '-inv' '1' >/dev/null ); [ "$?" = '7' ] || return 1

# Invalid version formats
( version_compare '1..0' '==' '1.0' >/dev/null ); [ "$?" = '7' ] || return 1
( version_compare '1.0' '==' '1..0' >/dev/null ); [ "$?" = '7' ] || return 1
( version_compare '1.0' '==' '1.0b7' >/dev/null ); [ "$?" = '7' ] || return 1
( version_compare '1.0a' '==' '1.0' >/dev/null ); [ "$?" = '7' ] || return 1

# "how does that handle comparing 10.0.0 (not a number) to 2.0 (a number)?"
( version_compare '10.0.0' '-lt' '2.0' ); [ "$?" = '1' ] || return 1
( version_compare '10.0' '-gt' '2.0.0' ); [ "$?" = '0' ] || return 1

# not less/greater-than... but equal
( version_compare '7' '-lt' '7' ); [ "$?" = '1' ] || return 1
( version_compare '7' '-gt' '7' ); [ "$?" = '1' ] || return 1

# String vs. numerical comparison
( version_compare '1.18.1' '-gt' '1.8.1' ); [ "$?" = '0' ] || return 1


# Random tests found on the internet
( version_compare '1' '==' '1' ); [ "$?" = '0' ] || return 1
( version_compare '2.1' '<' '2.2' ); [ "$?" = '0' ] || return 1
( version_compare '3.0.4.10' '>' '3.0.4.2' ); [ "$?" = '0' ] || return 1
( version_compare '4.08' '<' '4.08.01' ); [ "$?" = '0' ] || return 1
( version_compare '3.2.1.9.8144' '>' '3.2' ); [ "$?" = '0' ] || return 1
( version_compare '3.2' '<' '3.2.1.9.8144' ); [ "$?" = '0' ] || return 1
( version_compare '1.2' '<' '2.1' ); [ "$?" = '0' ] || return 1
( version_compare '2.1' '>' '1.2' ); [ "$?" = '0' ] || return 1
( version_compare '5.6.7' '==' '5.6.7' ); [ "$?" = '0' ] || return 1
( version_compare '1.01.1' '==' '1.1.1' ); [ "$?" = '0' ] || return 1
( version_compare '1.1.1' '==' '1.01.1' ); [ "$?" = '0' ] || return 1
( version_compare '1' '!=' '1.0' ); [ "$?" = '0' ] || return 1
( version_compare '1.0.0' '!=' '1.0' ); [ "$?" = '0' ] || return 1