The easiest way to do this in Bash is using sort -V
.
To solve the problem of comparing version strings in general in bash, here is an simple compare()
function that accepts two arguments a and b and returns true if a <= b. And then some unit tests showing its validity for various Python version inputs:
# test.sh
compare() {
local a=$1 ; local b=$2
[ "$( (echo "$a" ; echo "$b") | sort -V | head -1)" == "$a" ]
}
test22p1() {
compare "2.2p1" "3.0.0"
assertTrue "$?"
}
test214() {
compare "2.1.4" "3.0.0"
assertTrue "$?"
}
test300() {
compare "3.0.0" "3.0.0"
assertTrue "$?"
}
test372() {
compare "3.7.2" "3.0.0"
assertFalse "$?"
}
. shunit2
Output:
▶ bash test.sh
test22p1
test214
test300
test372
Ran 4 tests.
OK
(Those unit tests assume that shunit2 is installed of course.)
About the function:
It just echoes $a
then $b
on two separate lines, pipes into sort -V
, and takes the head. If the head is equal to the left-hand side, true is returned ; otherwise if it is equal to the right-hand side, false is returned.
In your question you mentioned you really want to know if Python 3 or greater is installed, so you could modify it and have something like this instead:
python3_installed() {
local a b
a=$(python --version 2>&1 | perl -pe 's/python *//i') ; b=3
[ "$( (echo "$a" ; echo "$b") | sort -V | head -1)" == "$b" ]
}
This function will compute the actual version of Python installed, and compare it to "3" using sort -V
and return false unless 3 or greater is installed.
Note use of Perl there to do a case-insensitive regex search and replace. (Not all sed's have the case-insensitive ability.)
The great thing about doing it this way is you can then have readable code when you call it, like:
if python3_installed ; then
# yes it is!
else
# ...
fi
Finally, according to the docs for sort -V
(from the BSD manual; POSIX doesn't specify a -V
option, but most sorts seem to have it):
`-V, --version-sort`
Sort version numbers. The input lines are treated as file names in form PREFIX VERSION SUFFIX, where SUFFIX matches the regular expression (.([A-Za-z~][A-Za-z0-9~]*)?)*
. The files are compared by their prefixes and versions (leading zeros are ignored in version numbers, see example below). If an input string does not match the pattern, then it is compared using the byte compare function. All string comparisons are performed in C locale, the locale environment setting is ignored.