Bash script error / integer expression expected [duplicate] - bash

To satisfy function requirements I have to retrieve a parameter which is a duty cycle (0-100% in 0.01%).
For test, I wrote something simple like :
#!/bin/bash
#
if [ "$1" -lt 0 ] || [ "$1" -gt 100 ]
then
echo "bad param"
else
echo "ok"
fi
I obtain :
root#:~# ./test.sh 11
ok
root#:~# ./test.sh 11,01
./test.sh: line 4: [: 11,01: integer expression expected
./test.sh: line 4: [: 11,01: integer expression expected
bad param
How to realise this kind of test ?

bash can only operate in integer arithmetics. If you need floats, use an external tool like bc:
if (( $( bc <<< "($1 < 0) || ($1 > 100) " ) )) ; then
...
fi
I would rather switch to a more powerful language for the whole script, though (like Perl)/

Related

decrement the variable value by 1 in shell

what is the correct syntax to decrement/decrease the variable value by 1 in while loop using /bin/sh and not using /bin/bash script
I used following but does not work
a=15
((a=a-1)) // not working
((a--)) // not working
EDIT 1
i=0
a=[]
b=15
while [ $a == [] ] && [ "$i" -le 15 ]
do
echo " Waiting ."
sleep 60s
((i=i+1))
b=`expr $b- 1`
a=`some command`
done
still getting following error
sh: was: unknown operand /bin/sh: exit: line 186: Illegal number: -1
Arithmetic substitution is spelled $(( )) and expands to the result. If you just need the side effect (e.g. increment), use it in a null command:
a=15
: $((--a))
echo $a
Note that shell arithmetic is integer only.
$ a=15
$ a=`expr $a - 1`
$ echo $a
14

How to return passed arguments in function in shell script?

Below is code which I developed. I am passing four arguments in function and want to return variable output which I am passing to that function as a argument number four. I am getting below mentioned error.
test.sh
output='PASS'
A=(1.0,1.0,1.0,1.0,0.0,1.0)
T=(1,2,3,4,5,6)
function compare(){
j=0
for i in "$2"
do
if [[ "$3" = '1.0' ]]
then
"$4"="PASS"
echo -e "\nA:$3 and T:$i sec" >> "$1"
else
"$4"="FAIL"
echo -e "\nA:$3 and T:$i sec" >> "$1"
fi
j=$(( $j + 1 ))
done
return "$4"
}
result=compare $1 ${A[#]} ${T[#]} output
echo "result:$result"
When I call ./test.sh file.txt, I get the following error:
./test.sh: line 13: output=FAILED: command not found
./test.sh: line 18: return: output: numeric argument required
result=
Lots of problems here:
trying to assign a value to a variable value (this is the cause of the "output=FAIL" error you see)
passing arrays as first-class values
collecting output of the function
It's still not clear how A and T are related (settle down, techbros), but it looks like T contains the index you want to look up in A.
#!/bin/bash
# validate the bash version at least 4.4 here.
function compare(){
local file=$1
local -n arrayA=$2
local -n arrayT=$3
local -n resultVar=$4
resultVar=PASS
for i in "${arrayT[#]}"; do
if [[ "${arrayA[i]}" != '1.0' ]]; then
resultVar=FAIL
# normally I would return here, but you want to log the whole array
fi
printf "A:%f and T:%d sec\n" "${arrayA[i]}" "$i" >> "$file"
done
}
output='PASS'
T=(1 2 3 4 5 6)
A=([1]=1.0 1.0 1.0 1.0 0.0 1.0) # force A to start with index 1, corresponding to the first element of T
compare "$1" A T output
echo "result:$output"

expr and if in bash

What's wrong with this code? If I input the number 25, it output failed instead of lol. Am I missing something?
read -p "Enter number : " num
if [ `expr $num > 5` ]
then
echo "lol"
else
echo "failed"
fi
The code
if [ `expr $num > 5` ]
actually does not do want you think. It will run expr $num > 5, so evaluate parameter and redirect the out to a file named 5 ("put 25 in a file named 5") and if will evaluate the return code of the previous expression.
If the code if meant to check evaluate if a number is bigger than 5, replace
if [ `expr $num > 5` ]
with
[ "$num" -gt 5 ]
-gt stands for greater than
#babtistemm's answer gives you the suggested solution but in case you insist on using (the bit oldish) expr for some reason:
read -p "Enter number : " num
if expr "$num" '>' 5 >/dev/null
then
echo "lol"
else
echo "failed"
fi
Notes:
You need to quote > so that the shell does not interpret it as redirecting the stdout. You could also use \>.
It is good practice to add double quotes to $num as well, so that expr will interpret it as one expression, thus limiting the chances of a very bad bug or a malicious user hacking your program. (Best would be to do a sanity-check on $num before using it, e.g. checking if it is an integer.)
This solution necessitates calling a new process, expr, which costs a lot more resource from the OS than using the test shell command only.
If you omit the >/dev/null, you will also get a 0 or 1 printed (meaning false or true), the stdout of expr. But independently of that, expr sets its exit status, $? according to the result of the expression, which is tested then by the if. (A side remark: if you try to echo $? after calling expr, it may come at a surprise first that $? = 0 means true/success as exit status, and $? != 0 means false by convention.)
you can use an arithmetic expression in bash:
if (( num > 5 )); then ...
In the manual, see https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructs
Same in a short line:
read -p 'Enter a number: ' num
(( num > 5 )) && echo lol || echo fail
could be condensed:
read -p 'Enter a number: ' num;((num>5))&&echo lol||echo fail
This syntaxe will work if first command success!
read -p 'Enter a number: ' num
((num > 5)) && {
echo lol
/bin/wrongcommand
:
} || echo fail
Could output:
lol
bash: /bin/wrongcommand: No such file or directory
But no fail because of : (is an alias for true) will alway success.
You could of course group command for fail:
read -p 'Enter a number: ' num
((num > 5)) && {
echo lol
/bin/wrongcommand
:
} || {
echo fail
other command
}
Could be written:
read -p 'Enter a number: ' num;((num>5))&&{ echo lol;/bin/wrongcommand;:;}||{ echo fail;other command;}
You could group commands between {  and ;} (care about the space after first {!)
Enter a number: 4
fail
bash: other: command not found
Enter a number: 7
lol
bash: /bin/wrongcommand: No such file or directory

convert read string to integer in bash

I'm trying to read from user and then do the following.
read framechoice
if [ $framechoice -gt 100 ]; then
if [ $framechoice -lt 0 ]; then
framechoice=101
fi
fi
It gives me the following error.
[: -gt: unary operator expected
Can anyone tell me where I am going wrong.
This happens if you don't input anything:
$ cat myscript
read framechoice
if [ $framechoice -gt 100 ]; then
if [ $framechoice -lt 0 ]; then
framechoice=101
fi
fi
$ bash myscript
<enter>
myscript: line 2: [: -gt: unary operator expected
Try instead to actually enter something:
$ bash myscript
42<enter>
The script then exits with success.
Your program needs to cope with empty input. This is most easily achieved by properly quoting the variable; then
if [ "$framechoice" -gt 100 ]; then
evaluates to [ "" -gt 100 ] which is no longer is a syntax error; however, instead, it throws the warning integer expression expected.
Even better, maybe filter the input so that you do not attempt numeric comparisons before making sure the input is numeric.

Bash in if check integer

I have created a script in bash. I need to check if take 0 number then ignore this, but if take some value then I need to calculate based on the value given and print the result.
Here is an example:
if [ "$max_users_conn" -ne "0" ]; then
let "percentage="$process_list"*100/"$max_users_conn""
echo "$percentage"
fi
However, when I run the code, I receive the following error:
./mysql_conn.sh: line 14: [: 0 10: integer expression expected
./mysql_conn.sh: line 14: [: 0 10: integer expression expected
./mysql_conn.sh: line 14: [: 5 5: integer expression expected 0 20
I also tried to run it like this:
if [ "$max_users_conn" != "0" ]; then
let "percentage="$process_list"*100/"$max_users_conn""
echo "$percentage"
fi
But this gives a different error:
./mysql_conn.sh: line 15: let: percentage=4*100/0: division by 0
(error token is "0")
./mysql_conn.sh: line 15: let: percentage=4*100/0: division by 0
(error token is "0")
0 0 20
Bash does not allow you math expressions like other languages do, you need to use the $(( ... )) operator for this. However, this operator gives you only operations base on integers if you supply integers: echo $((2/4)) # => 0. If you do not care about fractions, though, it will help you. If you need fractions, utilize bc like anubhava showed in his answer.
Additionally, you should check that $max_users_conn actually contains a value.
So, rewrite your snipped to look like this:
if [ -n "$max_users_conn" -a "$max_users_conn" -ne 0 ]; then
percentage=$(( $process_list * 100 / $max_users_conn))
echo "$percentage"
fi
test "$a" -ne 0 checks for numeric values, while test "$a" != "$b" checks for string equivalence.
In BASH you can do:
if [[ $max_users_conn -ne 0 ]]; then
percentage=$((process_list * 100 / max_users_conn))
echo "$percentage"
fi
but keep in mind that BASH doesn't support floating point maths and you will get an integer value returned.
To get decimal number returned use this bc command above.
percentage=$(bc -l <<< "scale=2; $process_list * 100 / max_users_conn")

Resources