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


当前回答

$ 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

其他回答

您可以通过版本命令行查看版本约束

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

Bash脚本示例:

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

我不喜欢这些解决方案,因为它们漏洞百出、不可移植等等。

我(目前)努力提出一个更好的解决方案……src: version_compare(),测试

Sorta-copied /贴在这里……

来源:

##
# 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 "$1" "$3"; _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 "$2" 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 [ "$1" -eq "$1" ] 2>/dev/null; then
                _exit_status="$1"; shift
        else
                _exit_status=1
        fi

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

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

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

    # Split versions on VER_SEP into int/sub
    _v="$1$2"
    _v1="$1"
    _s1="${1#*$VERSION_SEPARATOR}"
    if [ "$_v1" = "$_s1" ]; then
        _s1=''
        _m1="$_v1"
    else
        _m1="${1%%$VERSION_SEPARATOR*}"
    fi
    _v2="$2"
    _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

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

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

下面是另一个纯bash版本,比公认的答案要小得多。它只检查版本是否小于或等于“最小版本”,并且它将按字典顺序检查字母数字序列,这通常会给出错误的结果(举个常见的例子,“snapshot”不晚于“release”)。它将工作的主要/次要。

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
}

这在版本中最多为4个字段。

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