You are not logged in.
Pages: 1
Hi
Im working on this script, something to help me do some stuff quicker.
It reads number from file (that number is only thing in file),
num=`cat file.txt`
Let's say number is in 0.8.
If number is in between 0.2 and 1.4 it launches command, like echo "hi".
And if number is in between 1.4 and 2.8 it lounches other command.
I know how to do case, but only if there is exact number (like 4 or so), not with sequence of numbers.
How to do so?
Last edited by ammon (2010-11-12 20:50:10)
Offline
Originally I was going to answer:
num=`cat file.txt`
if [[ "$num" > "0.2" ]] && [[ "$sum" < "1.4" ]] ; then
echo "hi"
else
echo "bye"
fi
But then I remembered BASH doesn't support floating point arithmetic.
Probably the best thing to do would be to strip the decimal point, and add leading/trailing zeros if need be. Supposing that num is always given in the form 'x.y' with a single digit on each side you could just strip the '.':
num=`cat file.txt`
num=${num/./}
if [[ "$num" > "02" ]] && [[ "$sum" < "14" ]] ; then
echo "hi"
else
echo "bye"
fi
If num could take any form, or have any number of digits, then it gets more complicated. You might want to google "Floating point arithmetic in BASH", and you'll get a lot of workarounds.
Last edited by frabjous (2010-11-12 21:35:40)
Offline
why don't you use if statements? btw this is more pseudo code than anything.
#!/bin/bash
num=`cat file.txt`
if [[ $num > 0.2 && $num <= 1.4 ]]; then
#do something
elif [[ $num > 1.4 && $num <= 2.8 ]]; then
#do something else
else
#default do something
fi
I think Perl would be better suited for something like this however.
#!/usr/bin/perl
use strict;
use warnings;
use feature 'switch';
open(my $in, "<", "file.txt") or die "Cuidado! Piso Mojado!";
chomp(my $value = <$in>);
given($value){
when($value > 0.2 && $value <= 1.4)
{
print "hey guy!\n";
}
when($value > 1.4 && $value <= 2.8)
{
system("ls -la"); #or ANY command!
}
default
{
die "ACHTUNG!";
}
}
close($in);
generally, Perl will handle the floating point arithmetic better than bash, and provide you with a much more flexible switch statement.
EDIT: oops, forgot to close my file
Last edited by Cyrusm (2010-11-12 22:31:49)
Hofstadter's Law:
It always takes longer than you expect, even when you take into account Hofstadter's Law.
Offline
Ok, so if I multiply every number with 100. So if there was 0.44 it will be 44.
Then, what would be solution?
Btw, I tried to do it like this. But it does not work, can you tell me why?
num=55
avg=`seq 47 1 79`
norm=`seq 80 1 139`
low=`seq -80 1 39`
case $num in
"$avg" )
echo "ok"
;;
"$norm" )
echo "fine"
;;
"$low" )
echo "lol"
;;
esac
Last edited by ammon (2010-11-12 21:47:25)
Offline
Originally I was going to answer:
num=`cat file.txt` if [[ "$num" > "0.2" ]] && [[ "$sum" < "1.4" ]] ; then echo "hi" else echo "bye" fi
But then I remembered BASH doesn't support floating point arithmetic.
That's what I thought when I saw your reply, but I tried few numbers, it seems to work well with string comparison.
However, I would use `bc`:
$ bc <<< "0.5 > 0.2 && 0.5 < 1.4"
1
$ bc <<< "0.0 > 0.2 && 0.0 < 1.4"
0
$ bc <<< "-1.0 > 0.2 && -1.0 < 1.4"
0
Maybe awk is a better option if not really have to use pure Bash script?
Offline
why don't you use if statements? btw this is more pseudo code than anything.
#!/bin/bash num=`cat file.txt` if [[ $num > 0.2 && $num <= 1.4 ]]; then #do something elif [[ $num > 1.4 && $num <= 2.8 ]]; then #do something else else #default do something fi
Yes, that does the trick. Thank you.
But I have problem, it does not work with <=, and number sometimes matches final number (in this case 1.4)
line 4: syntax error in conditional expression
/ line 4: syntax error near `1.4'
line 4: `if [[ $num > 0.2 && $num <= 1.4 ]]; then'
I have to use bash. Ty for perl way, but I can't use it.
Offline
Your idea of multiplying everything by 100 should work, but the question is: how? You can't just multiply "0.4" by 100 in BASH, since BASH can't do any math for strings with decimal points in them.
You can't just remove the decimal point, or you might get wrong results if there aren't exactly 2 decimal places in the value. You don't want it, for example, to think of "1.233" as greater than "10.1".
But you could, e.g., split the num variable into the part before the period, and the point after, and then pad the decimal part with 0s if if were less than 2 characters long, and strip it to two characters if it is more than that.
This feels unnecessarily complicated, but here goes:
# set numwholepart to part of num before .
numwholepart=${num%.*}
# set numdecimalpart to part after .
numdecimalpart=${num#*.}
# if there was no period in the expression
# then you need to make it 00
if [ "$num" == "$numdecimalpart" ] ; then
numdecimalpart="00"
fi
# count how many digits numdecimalpart has
numdecimalplaces=${#numdecimalpart}
# pad it to the right size
if [ "$numdecimalplaces" == "0" ] ; then
numdecimalpart="00" # if there was no digits after .
elif [ "$numdecimalplaces" == "1" ] ; then
numdecimalpart="${numdecimalpart}0" # if there was only 1
else
numdecimalpart="${numdecimalpart:0:2}" # if there two or more cut it 2
fi
# create combined number by putting whole part before decimal part
numcompare="$numwholepart$numdecimalpart"
# now the number needs to be between 20 and 140
if [ $numcompare -ge 20 ] && [ $numcompare -lt 140 ] ; then
echo "yes"
else
echo "no"
fi
Offline
Cyrusm wrote:why don't you use if statements? btw this is more pseudo code than anything.
#!/bin/bash num=`cat file.txt` if [[ $num > 0.2 && $num <= 1.4 ]]; then #do something elif [[ $num > 1.4 && $num <= 2.8 ]]; then #do something else else #default do something fi
Yes, that does the trick. Thank you.
But I have problem, it does not work with <=, and number sometimes matches final number (in this case 1.4)
line 4: syntax error in conditional expression
/ line 4: syntax error near `1.4'
line 4: `if [[ $num > 0.2 && $num <= 1.4 ]]; then'I have to use bash. Ty for perl way, but I can't use it.
No. This does not work. Bash cannot compare floating point numbers. You are getting false positives as a result of a lexicographical comparison.
[[ 2 > 10 ]] && echo yes
Offline
man expr people!
if [ $(expr 0.5 '>' 0.2) -eq 1 ]; then
echo greater
fi
Last edited by tavianator (2010-11-13 06:15:01)
Offline
man expr people!
No, expr does not handle floating point arithmetic properly.
$ if [ $(expr 20.0 '>' 100.0) -eq 1 ]; then echo greater; fi
greater
Since when is 20 greater than 100? It isn't. It just comes after it alphabetically.
Last edited by frabjous (2010-11-13 06:53:10)
Offline
@ammon I don't know what you mean by "with sequence of numbers"... maybe you need a while loop? Please post a sample file for clarification.
Anyway, I think I've found a way to do float number comparision with pure bash, by compare the int part and float part separately:
#!/bin/bash
cmp_float()
{
local p a b a_l a_r b_l b_r
p=${3:-2} # precision
a=$(printf %.${p}f $1)
b=$(printf %.${p}f $2)
a_l=${a%.*}; a_r=${a#*.}
b_l=${b%.*}; b_r=${b#*.}
if (($a_l == $b_l)); then
cmp $a_r $b_r
else
cmp $a_l $b_l
fi
}
cmp()
{
if (($1 == $2)); then
echo 0
elif (($1 > $2)); then
echo 1
elif (($1 < $2)); then
echo -1
fi
}
cmp_float $1 $2
Edit:
Oops, didn't see post #7. Haha, gr8t mindz th1nk 'like.
Last edited by lolilolicon (2010-11-13 07:51:22)
This silver ladybug at line 28...
Offline
tavianator wrote:man expr people!
No, expr does not handle floating point arithmetic properly.
$ if [ $(expr 20.0 '>' 100.0) -eq 1 ]; then echo greater; fi greater
Since when is 20 greater than 100? It isn't. It just comes after it alphabetically.
Huh, well I feel silly. I'd go with bc then, or use zsh (which does support floating point arithmetic).
Offline
I think that in scenarios like this script languages like python or pearl are more suitable.
Offline
I guess awk would be the most common tool to reach for at this point:
gt_awk() { awk "BEGIN { exit ($1 > $2) ? 0 : 1 }" ;}
I think that in scenarios like this script languages like python or pearl are more suitable.
May I recommend lua? It is amazingly small and fast, so for things like this it is ideal:
gt_lua() { lua -e "os.exit( ($1 > $2) and 0 or 1 )" ;}
If you want to take it one step further and write the whole thing in lua, the io module for reading the file and os.execute() to call external commands will be all you need.
Just for curiosity's sake:
gt_perl() { perl -e "exit (($1 > $2) ? 0 : 1)" ;}
And for completeness (be careful that here 0 is false and 1 is true, unlike bash exit codes):
gt_bc() { bc <<< "$1 > $2" ;}
An amazingly oversimplified comparison:
$ time for i in {1..1000}; do gt_awk 0.8 1.4 >/dev/null; done
real 0m5.571s
user 0m2.873s
sys 0m0.787s
$ time for i in {1..1000}; do gt_perl 0.8 1.4 >/dev/null; done
real 0m3.237s
user 0m0.347s
sys 0m0.237s
$ time for i in {1..1000}; do gt_bc 0.8 1.4 >/dev/null; done
real 0m3.027s
user 0m0.200s
sys 0m0.247s
$ time for i in {1..1000}; do gt_lua 0.8 1.4 >/dev/null; done
real 0m1.594s
user 0m0.133s
sys 0m0.183s
A large part of this time would be starting the interpreter, but for the small script the OP needs it is still significant. Of course perl and lua can read the file themselves, thus the entire script could be in those languages.
BTW: If you google "bash floating point" you should come up with enough results to figure out how you could solve this.
Offline
That's a nice plug for Lua, quigybo. I've been thinking about which of several languages to learn next, and while this seems like a very small and tiny consideration, somehow it does push me a little more towards Lua (which I had been considering anyway, for other reasons).
Out of curiousity, I tried Python for comparison:
$ gt_python() { python -c "($a > $b) or exit(1)" ;}
$ time for i in {1..1000}; do gt_python 0.8 1.4 >/dev/null; done
real 0m26.838s
user 0m18.192s
sys 0m5.580s
Ouch! That took forever.
For comparison, here are my values for the other functions. bc was actually faster than lua, and perl did quite well too.
$ time for i in {1..1000}; do gt_bc 0.8 1.4 >/dev/null; done
real 0m1.102s
user 0m0.060s
sys 0m0.147s
$ time for i in {1..1000}; do gt_lua 0.8 1.4 >/dev/null; done
real 0m1.171s
user 0m0.080s
sys 0m0.153s
$ time for i in {1..1000}; do gt_perl 0.8 1.4 >/dev/null; done
real 0m2.053s
user 0m0.070s
sys 0m0.187s
$ time for i in {1..1000}; do gt_awk 0.8 1.4 >/dev/null; done
real 0m3.608s
user 0m1.723s
sys 0m0.587s
Last edited by frabjous (2010-11-16 22:01:33)
Offline
Guys, thanks for the replies.
But I will need further help. I don't understand half of this you wrote.
Ok, bash is outta question, but I can use zsh and python.
Actually I was working in zsh. But I did not mention it becouse I tought it is not important.
So, what I need is:
I have list of numbers, so it is a file with list of numbers.
It is not problem to read from it. Ok, lets move on.
Number is readed and compared to designated values,
I have this "border values", like first is:
0.8 and 2.0 (numbers can be $num >= 0.8),
-0.38 to 0.38 ($num can also be >= 0.38)
I have 5 such cases. And for each I have command that louches something after considering where number belongs.
So...
if $num > 0.8
cat /etc/blabla > file.txt
if $num >= -0.39 to =< 0.39
cat /etc/blabla1 > file.txt
P.S.
Someone mentioned awk. How to do this with awk?
Last edited by ammon (2010-11-17 22:17:44)
Offline
Pages: 1