Как сравнить версии некоторых продуктов в unix KSH shell?
Формат версий-X. X. X. X.
Где X-число.
Как лучше всего сравнить две версии?
Я использую следующий код:
compareVersions()
{
VER_1=$1
VER_2=$2
print -R "$VER_1"| IFS=. read v1_1 v1_2 v1_3 v1_4
print -R "$VER_2"| IFS=. read v2_1 v2_2 v2_3 v2_4
RESULT="0"
if [[ "${v1_1}" -lt "${v2_1}" ]]
then
RESULT="-1"
elif [[ "${v1_1}" -gt "${v2_1}" ]]
then
RESULT="1"
elif [[ "${v1_2}" -lt "${v2_2}" ]]
then
RESULT="-1"
elif [[ "${v1_2}" -gt "${v2_2}" ]]
then
RESULT="1"
elif [[ "${v1_3}" -lt "${v2_3}" ]]
then
RESULT="-1"
elif [[ "${v1_3}" -gt "${v2_3}" ]]
then
RESULT="1"
elif [[ "${v1_4}" -lt "${v2_4}" ]]
then
RESULT="-1"
elif [[ "${v1_4}" -gt "${v2_4}" ]]
then
RESULT="1"
fi
echo "$RESULT"
}
Но мне это не нравится - все очень просто.
Может быть, есть более правильный способ сравнить версии?




Ответы - Как сравнить версии некоторых продуктов в unix KSH shell? / How to compare versions of some products in unix ksh shell?

18.08.2010 02:28:22
Может быть, вы могли бы использовать awk
?
echo $VER_1 $VER2 | \
awk '{ split($1, a, ".");
split($2, b, ".");
for (i = 1; i <= 4; i++)
if (a[i] < b[i]) {
x =-1;
break;
} else if (a[i] > b[i]) {
x = 1;
break;
}
print x;
}'
Нет идеального способа сделать это. Как показано, вы можете использовать массив / цикл для чисел, также в bash
.

sort -V
недостаточно широко поддерживается, и использование awk
позволяет избежать необходимости в специальных встроенных функциях.

for
на for (i = 1; !x && i <= 4; ++i) x = (a[i] < b[i]) ? -1 : ((a[i] > b[i]) ? 1 : 0);

18.08.2010 02:32:39
Чистый Баш / КШ:
compareVersions ()
{
typeset IFS='.'
typeset -a v1=( $1 )
typeset -a v2=( $2 )
typeset n diff
for (( n=0; n<4; n+=1 )); do
diff=$((v1[n]-v2[n]))
if [ $diff -ne 0 ] ; then
[ $diff -le 0 ] && echo '-1' || echo '1'
return
fi
done
echo '0'
} # ---------- end of function compareVersions ----------


09.09.2011 11:52:18
Если вы можете обмануть, используя Perl в своем скрипте оболочки, попробуйте встроенную обработку строк версии с помощью операторов сравнения строк:
V1=1.1.3; V2=1.1
echo $(perl -e '($x,$y)=@ARGV; print $x cmp $y' $V1 $V2)
Вы также можете отказаться от переменных Perl и просто использовать shift:
result=$(perl -e 'print shift cmp shift' $V1 $V2)
Но это не удается на версиях > 10. Так что вы можете попробовать это вместо этого:
perl -e '($a,$b)=@ARGV; for ($a,$b) {s/(\d+)/sprintf "%5d", $1/ge}; print $a cmp $b;' 12.1.3 9.0.2
Sprintf "%5d " должен быть уверен, что он будет работать даже для Firefox, до версии 99999... :-)
Очевидно, что вы также можете использовать другие строковые операторы Perl, такие как gt, lt, ge и le.

10.03.2013 07:42:24
Вы можете использовать sort -V
для сортировки строк с версиями и сопоставления вашей версии с выводом:
% cat sorttest
#!/bin/sh
version_lt() {
echo "$1\n$2" | sort -V | head -n 1 | grep -q "$1"
}
display_versioncmp() {
version_lt "$1" "$2" && echo "$1 < $2" || echo "$1 > $2"
}
X="1.2.3"
Y="11.2.3"
Z="1.22.3"
display_versioncmp "$X" "$Y"
display_versioncmp "$Y" "$X"
display_versioncmp "$X" "$Z"
display_versioncmp "$Z" "$X"
display_versioncmp "$Z" "$Y"
display_versioncmp "$Y" "$Z"
% ./sorttest
1.2.3 < 11.2.3
11.2.3 > 1.2.3
1.2.3 < 1.22.3
1.22.3 > 1.2.3
1.22.3 < 11.2.3
11.2.3 > 1.22.3

sort -V
. (Например, Мак может и не знать.)



14.08.2013 08:27:32
У меня была эта проблема, и после ее решения я посмотрел, есть ли уже лучший ответ. Моя версия позволяет сравнивать строки версий разной длины и является функцией version_ge() ниже, которая должна использоваться как оператор "больше или равно", как в
если version_ge "$version" "1.2.3.4"; то ...
#!/bin/sh
# Usage: split "<word list>" <variable1> <variable2>...
# Split a string of $IFS seperated words into individual words, and
# assign them to a list of variables. If there are more words than
# variables then all the remaining words are put in the last variable;
# use a dummy last variable to collect any unwanted words.
# Any variables for which there are no words are cleared.
# eg. split 'hello Fred this is Bill' greeting who extra
# sets greeting=hello who=Fred extra="this is Bill"
# and split "$list" word list # "pops" the first word from a list
split()
{
# Prefix local names with the function name to try to avoid conflicts
# local split_wordlist
split_wordlist="$1"
shift
read "$@" <<EOF-split-end-of-arguments
${split_wordlist}
EOF-split-end-of-arguments
}
# Usage: version_ge v1 v2
# Where v1 and v2 are multi-part version numbers such as 12.5.67
# Missing .<number>s on the end of a version are treated as .0, & leading
# zeros are not significant, so 1.2 == 1.2.0 == 1.2.0.0 == 01.2 == 1.02
# Returns true if v1 >= v2, false if v1 < v2
version_ge()
{
# Prefix local names with the function name to try to avoid conflicts
# local version_ge_1 version_ge_2 version_ge_a version_ge_b
# local version_ge_save_ifs
version_ge_v1="$1"
version_ge_v2="$2"
version_ge_save_ifs="$IFS"
while test -n "${version_ge_v1}${version_ge_v2}"; do
IFS="."
split "$version_ge_v1" version_ge_a version_ge_v1
split "$version_ge_v2" version_ge_b version_ge_v2
IFS="$version_ge_save_ifs"
#echo " compare $version_ge_a $version_ge_b"
test "0$version_ge_a" -gt "0$version_ge_b" && return 0 # v1>v2: true
test "0$version_ge_a" -lt "0$version_ge_b" && return 1 # v1<v2:false
done
# version strings are both empty & no differences found - must be equal.
return 0 # v1==v2: true
}

23.01.2020 06:28:27
Вот немного улучшенный метод, ранее опубликованный schot. Этот метод может спасти вашу жизнь, когда нет Баш, вроде -в команды и т. д. (например, в некоторых изображениях docker).
compareVersions() {
echo $1 $2 | \
awk '{ split($1, a, ".");
split($2, b, ".");
res = -1;
for (i = 1; i <= 3; i++){
if (a[i] < b[i]) {
res =-1;
break;
} else if (a[i] > b[i]) {
res = 1;
break;
} else if (a[i] == b[i]) {
if (i == 3) {
res = 0;
break;
} else {
continue;
}
}
}
print res;
}'
}