是否有办法在bash上比较这些字符串,例如:2.4.5和2.8和2.4.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"
其他回答
我不喜欢这些解决方案,因为它们漏洞百出、不可移植等等。
我(目前)努力提出一个更好的解决方案……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
我实现了另一个比较器函数。这一个有两个特定的要求:(i)我不希望函数失败使用返回1,但echo代替;(ii)当我们从git存储库中检索版本时,版本“1.0”应该大于“1.0.2”,这意味着“1.0”来自trunk。
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
}
请随意评论并提出改进建议。
这里一个有用的技巧是字符串索引。
$ echo "${BASH_VERSION}"
4.4.23(1)-release
$ echo "${BASH_VERSION:0:1}"
4
你们都给出了复杂的解决方案。这里有一个更简单的例子。
function compare_versions {
local a=${1%%.*} b=${2%%.*}
[[ "10#${a:-0}" -gt "10#${b:-0}" ]] && return 1
[[ "10#${a:-0}" -lt "10#${b:-0}" ]] && return 2
a=${1:${#a} + 1} b=${2:${#b} + 1}
[[ -z $a && -z $b ]] || compare_versions "$a" "$b"
}
用法:compare_versions <ver_a> <ver_b>
返回代码1表示第一个版本大于第二个版本,2表示小于第二个版本,0表示两者相等。
也是一个非递归的版本:
function compare_versions {
local a=$1 b=$2 x y
while [[ $a || $b ]]; do
x=${a%%.*} y=${b%%.*}
[[ "10#${x:-0}" -gt "10#${y:-0}" ]] && return 1
[[ "10#${x:-0}" -lt "10#${y:-0}" ]] && return 2
a=${a:${#x} + 1} b=${b:${#y} + 1}
done
return 0
}
对于旧版本/busybox排序。简单的形式提供了粗略的结果,往往奏效。
sort -n
这是特别有用的版本,其中包含alpha符号,如
10.c.3
10.a.4
2.b.5