BASH comparing Linux version to number? [duplicate] - bash

This question already has answers here:
How to compare two strings in dot separated version format in Bash?
(38 answers)
Closed 4 years ago.
I'm trying to work out how to compare the current openSuSE version number to a preset value.
I've got the current version of the installed OS in $VERSION_ID
I'm now trying to work out how to compare that to '42.3'. So if the value isn't greater than or equal to quit.
if [ ! "$VERSION_ID" -ge 42.3 ]; then
echo "Sorry Bye";
fi
I'm getting:
[: 42.3: integer expression expected But I don't know how to fix that
Any advise please
Thanks

You can use a calculator bc:
if [ $(echo "$VERSION_ID<=42.3" |bc -l) -eq "1" ]; then
echo "Sorry Bye";
fi

Version numbers aren't floating point values; they are .-delimited sequences of integers. 42.27 is newer than 42.3, and 42.2.9 could be a valid version number.
Split the version number into its integer components, and compare them "lexiconumerically":
target=(42 3)
IFS=. read -a v_id <<< "$VERSION_ID"
for ((i=0; i <${#v_id[#]}; i++)); do
if (( ${v_id[i]} == ${target[i]} )); then
continue
fi
if (( ${v_id[i]} < ${target[i]} )); then
echo "version < target"
elif (( ${v_id[i]} > ${target[i]} )); then
echo "version > target"
fi
break
done

Related

Comparing two versions [duplicate]

This question already has answers here:
How to compare two strings in dot separated version format in Bash?
(38 answers)
Closed 4 months ago.
I am have the toughest time with this and was wondering if anyone can help. I'm trying to compare two versions and output something if a version is old. Here is an example of what I have.
monterey="17612.4.9.1.8"
version=$(defaults read /Applications/Safari.app/Contents/Info.plist CFBundleVersion)
if [ "$version" -ge "$monterey" ] ; then
echo "Up to date"
else
echo "Needs update"
fi
exit 0
What I'd like for it to do is compare the Safari "version" version to the "monterey" version. If Safari is greater than or equal to "Monterey" then echo "Up to date".
But every time I try to do this I get "integer expression expected" or if I try >= I get "unary operator expected".
How should this be written?
17612.4.9.1.8 cannot be considered as an integer. Not even as a number: too many dots. If you want to compare dot-separated versions you must do this one field at a time, starting from the major version number.
One option is to store the fields in an array:
$ m=(${monterey//./ })
$ echo ${m[0]}
17612
$ echo ${#m[#]}
5
m=(${monterey//./ }) replaces all dots in $monterey by spaces and stores the result in array m, one space-separated word per cell. ${#m[#]} expands as the size of the array. So, something like the following should do what you want:
m=(${monterey//./ })
v=(${version//./ })
(( n = ${#v[#]} < ${#m[#]} ? ${#m[#]} : ${#v[#]} ))
for (( i=0; i < n; i++ )); do
if (( ${v[i]:-0} < ${m[i]:-0} )); then
echo "Needs update"
break
elif (( ${v[i]:-0} > ${m[i]:-0} )); then
echo "Up to date"
break
fi
done
exit 0
(( n = ${#v[#]} < ${#m[#]} ? ${#m[#]} : ${#v[#]} )) stores the largest array size in variable n. ${v[i]:-0} expands as v[i] if it is set and not the empty string, else as 0.
But if you can use sort, instead of plain bash, you can also use:
l=$(printf '%s\n%s\n' "$monterey" "$version" | sort -nt. | tail -n1)
if [[ $version = $l ]]; then
echo "Up to date"
else
echo "Needs update"
fi
exit 0
The first command sorts the two versions numerically (-n), using . as separator (-t.), keeps only the last (tail -n1), that is, the largest, and stores it in variable l. Note that this could not work as you would like if you can have trailing 0 fields: 1.2.0.0 will be considered as larger than 1.2.0 or 1.2.
As mentioned by #markp-fuso, if your sort utility supports it (it is a non-POSIX feature found, for instance, in the GNU coreutils sort), you can also use its -V option that does exactly what you want:
l=$(printf '%s\n%s\n' "$monterey" "$version" | sort -V | tail -n1)
-ge is used for numerical comparison operations.
This is to determine whether the strings are equal, you should use [ "$version" = "$monterey" ]

How can I check if a variable that need to contain a number has been set? [duplicate]

This question already has answers here:
How do I test if a variable is a number in Bash?
(40 answers)
How to check if a variable is set in Bash
(38 answers)
Closed 4 years ago.
Given the following code:
Max=
if [[ something exists.. ]]; then
Max=2
// .. more code that can changes the value of Max
fi
// HERE
How can I check at "HERE" if Max is equal to some number (setted)?
if [ -z "$Max" ]
then
echo "Max: not set"
else if [ $Max -eq some_number ]
then
echo "Max is equal to some number"
else
echo "Max is set but not equal to some number"
fi
or
if [ -n "$Max" -a "$Max" = "some_number" ]
...
Notice that the second example is doing a string comparison which can solve some headaches but may hurt the sensibilities of purists.
Cool !
Max is set by default to an empty value, that when used in an arithmetic context, returns zero. For example:
Try running echo $(( definitelyNotAGivenName)) it comes out as zero, cool!
You can use the round brackets for arithmetic comparing - see more here and here

Bash: check if one decimal number is greater than another decimal number [duplicate]

This question already has answers here:
How can I compare two floating point numbers in Bash?
(22 answers)
Closed 5 years ago.
I have a case like this:
string1="some_string"
string2="some_string"
int1="0.87"
int2="${var}"
$var is the output of some other script, and it has the form 0.994343123 or 0.3454657 or whatever (starts with 0. and the biggest value is around 0.9972343)
Now, I don't know how bash works, but usually string 0.87 is never less than or equal to 0.9999999, they are just different.
I would need something like this (pseudocode):
if (string1 equals string2 and int1 is less than int2):
do something;
else
do something else.
What i would expect is 0.87687 is greater than 0.87 (correct?? i was never good at math...)
Can anyone help me with the code for that if??
Thanks in advance!
Since bash does not handle floating point arithmetic, you may use bc -l to compare 2 floating point numbers and join the condition with && as:
if [[ $string1 = $string2 && $(bc -l <<< "$int1 < $int2") -eq 1 ]]; then
echo "yes"
else
echo "no"
fi
If the values are between 0 and 1, string comparison will work
s1=..; s2=..
v1="0.876"; v2="0.87"
[[ $s1 = $s2 && $v1 > $v2 ]] && echo yes || echo no
a=0.86
b=0.865
if ((`echo $a '<' $b|bc`)); then echo 'a<b'; fi
(You can replace the last line by
if (($(echo $a '<' $b|bc))); then echo 'a<b'; fi
but imho it is less readable)

How to iterate through variables? [duplicate]

This question already has answers here:
How to zero pad a sequence of integers in bash so that all have the same width?
(15 answers)
Closed 5 years ago.
I was using the following in my current script
for x in {07..10}
Trying to pass the start,end variables to the script using
for x in $(seq $1 $2)
Since the sequence starts from 07, and 07 is a file name that I want to read, I cant change the variable to 7, as it happens when using the sequence. Can you please point me in the right direction as I don't have much experience with bash.
Use printf to get the number format you want:
for (( x=7; x<=10; x++ )); do
str=$( printf "%02d" "$x" )
echo filename${str}.txt
done
Results look like this:
$ for (( x=7; x<=10; x++ )); do str=$( printf "%02d" "$x" ); echo filename${str}.txt; done
filename07.txt
filename08.txt
filename09.txt
filename10.txt
Works with variables, too:
$ start="07"
$ end="10"
$ for (( x=$start; x<=$end; x++ )); do str=$( printf "%02d" "$x" ); echo filename${str}.txt; done
filename07.txt
filename08.txt
filename09.txt
filename10.txt

In bash shell script how do I convert a string to an number [duplicate]

This question already has answers here:
How can I compare two floating point numbers in Bash?
(22 answers)
Closed 3 years ago.
Hey I would like to convert a string to a number
x="0.80"
#I would like to convert x to 0.80 to compare like such:
if[ $x -gt 0.70 ]; then
echo $x >> you_made_it.txt
fi
Right now I get the error integer expression expected because I am trying to compare a string.
thanks
you can use bc
$ echo "0.8 > 0.7" | bc
1
$ echo "0.8 < 0.7" | bc
0
$ echo ".08 > 0.7" | bc
0
therefore you can check for 0 or 1 in your script.
If your values are guaranteed to be in the same form and range, you can do string comparisons:
if [[ $x > 0.70 ]]
then
echo "It's true"
fi
This will fail if x is ".8" (no leading zero), for example.
However, while Bash doesn't understand decimals, its builtin printf can format them. So you could use that to normalize your values.
$ x=.8
$ x=$(printf %.2 $x)
$ echo $x
0.80
For some reason, this solution appeals to me:
if ! echo "$x $y -p" | dc | grep > /dev/null ^-; then
echo "$x > $y"
else
echo "$x < $y"
fi
You'll need to be sure that $x and $y are valid (eg
contain only numbers and zero or one '.') and,
depending on how old your dc is, you may need to
specify something like '10k' to get it to
recognize non-integer values.
Here is my simple solution:
BaseLine=70.0
if [ $string \> $BaseLine ]
then
echo $string
else
echo "TOO SMALL"
fi
use awk
x="0.80"
y="0.70"
result=$(awk -vx=$x -vy=$y 'BEGIN{ print x>=y?1:0}')
if [ "$result" -eq 1 ];then
echo "x more than y"
fi
The bash language is best characterized as a full-featured macro processor, as such there is no difference between numbers and strings. The problem is that test(1) works on integers.

Resources