if $NUMBER -lt .04 echo Lower
When $NUMBER is a decimal I get a "integer expression expected" error.
Ian
Most shells can only deal with integers (ksh93, available from
kornshell.com, is an exception).
Sometimes, comparing just the integer portion is accurate enough,
If that's the case:
[ ${NUMBER1%.*} -lt ${NUMBER2%.*} ] && echo Lower
If a comparison of the decimal portion is important, use a tool
that understands decimal fractions, such as awk or bc; or, these
shell functions will do the job.
int - return the integer portion of a decimal number
return 0 if there is no integer portion
frac - return the decimal portion of a decimal number
return 0 if there is no decimal portion
fpcompare - if the first argument is greater than the second, return 1
if the first argument is less than the second, return -1
if the two arguments are equal, return 0
The result of each function is placed in a variable whose name is
the name of the function converted to upper case and preceded by an
underscore (e.g., int stores its result in _INT).
The result is echoed if _SILENT_FUNCS is not set to 1.
### the functions:
int() {
_INT=0
case $1 in
.*|"") _INT=0 ;;
*.*) _INT=${1%.*} ;;
*) _INT=$1 ;;
esac
[ "$_SILENT_FUNCS" = 1 ] || echo ${_INT}
}
dec() {
_DEC=0
case $1 in
.*) _DEC=${1#?} ;;
*.) _DEC=0 ;;
*.*) _DEC=${1#*.} ;;
esac
[ "$_SILENT_FUNCS" = 1 ] || echo ${_DEC}
}
fpcompare() {
[ $# = 2 ] || { _FPCOMPARE=5; return 5; }
neg1=
neg2=
case $1 in -*) neg1=-; num1=${1#-} ;; esac
case $2 in -*) neg2=-; num2=${2#-} ;; esac
_FPCOMPARE=0
_SILENT_FUNCS=1 int $num1
int1=$_INT
_SILENT_FUNCS=1 int $num2
int2=$_INT
if [ "$neg1$int1" -gt "$neg2$int2" ]
then
_FPCOMPARE=1
elif [ "$neg1$int1" -lt "$neg2$int2" ]
then
_FPCOMPARE=-1
else
_SILENT_FUNCS=1 dec $1
dec1=$_DEC
_SILENT_FUNCS=1 dec $2
dec2=$_DEC
while [ ${#dec1} -ne ${#dec2} ]
do
[ ${#dec1} -gt ${#dec2} ] && dec2=${dec2}0
[ ${#dec2} -gt ${#dec1} ] && dec1=${dec1}0
done
if [ "$neg1$dec1" -gt "$neg2$dec2" ]
then
_FPCOMPARE=1
elif [ "$neg1$dec1" -lt "$neg2$dec2" ]
then
_FPCOMPARE=-1
fi
fi
[ "$_SILENT_FUNCS" = 1 ] || echo ${_FPCOMPARE}
}
--
Chris F.A. Johnson http://cfaj.freeshell.org
===================================================================
My code (if any) in this post is copyright 2003, Chris F.A. Johnson
and may be copied under the terms of the GNU General Public License
Bash does not do floating point arithmetic. Use bc or something.
> if $NUMBER -lt .04 echo Lower
Peter
[interesting samples deleted]
Often you can use the power of other utilities, rather than being
restricted to pure shell builtins:
fpcompare() {
_FPCOMPARE=`echo $1 $2 - p | dc`
if test 0 == $_FPCOMPARE
then
echo 0
else
echo X $_FPCOMPARE | grep -- - >/dev/null && echo -1 || echo 1
fi
}
For the purposes of the illustration my code ignores CFAJ's _SILENT_FUNCS
flag, which would be trivial to incorporate if required.
Regards,
Chris
--
@s=split(//,"Je,\nhn ersloak rcet thuarP");$k=$l=@s;for(;$k;$k--){$i=($i+1)%$l
until$s[$i];$c=$s[$i];print$c;undef$s[$i];$i=($i+(ord$c))%$l}
Depending on your requirements, you might do
if ($NUMBER * 100) -lt 4) echo Lower
I assume earlier your shell script says something like:
declare -i NUMBER
--
.~. Jean-David Beyer Registered Linux User 85642.
/V\ Registered Machine 73926.
/( )\ Shrewsbury, New Jersey http://counter.li.org
^^-^^ 10:25am up 1 day, 13:00, 3 users, load average: 2.13, 2.14, 2.12
>> fpcompare - if the first argument is greater than the second, return 1
>> if the first argument is less than the second, return -1
>> if the two arguments are equal, return 0
>
> [interesting samples deleted]
Also deleted was:
|| If a comparison of the decimal portion is important, use a tool
|| that understands decimal fractions, such as awk or bc; ....
> Often you can use the power of other utilities, rather than being
> restricted to pure shell builtins:
>
> fpcompare() {
> _FPCOMPARE=`echo $1 $2 - p | dc`
> if test 0 == $_FPCOMPARE
> then
> echo 0
> else
> echo X $_FPCOMPARE | grep -- - >/dev/null && echo -1 || echo 1
> fi
> }
$ fpcompare -12.14244 -12.33
dc: stack empty
dc: stack empty
-1
man dc:
To enter a negative number, begin the number with ``_''.
``-'' cannot be used for this, as it is a binary operator for
subtraction instead.
Try:
_FPCOMPARE=`echo "${1/-/_} ${2/-/_} - p" | dc`
Or use bc:
_FPCOMPARE=`echo $1 - $2 | bc`
And there's no need for grep:
fpcompare() {
case `echo $1 - $2 | bc` in
-*) _FPCOMPARE=-1 ;;
0) _FPCOMPARE=0 ;;
*) _FPCOMPARE=1 ;;
esac
[ "$_SILENT_FUNCS" = 1 ] || echo ${_FPCOMPARE}
}
The fastest external command for this is awk:
fpcompare() {
_FPCOMPARE=`awk "BEGIN { x = $1 - $2
if ( x == 0 ) print 0
else if ( x < 0 ) print -1
else print 1
}"`
[ "$_SILENT_FUNCS" = 1 ] || echo $_FPCOMPARE
}
> For the purposes of the illustration my code ignores CFAJ's _SILENT_FUNCS
> flag, which would be trivial to incorporate if required.
Yes... I should probably have used bc in this case. However, bc only
works to the number of decimal places provided in its input, and I've
been bitten by echo 1 / 3 | bc ==> 0 type problems so many times I have
an anathema to using it in anything!
> To enter a negative number, begin the number with ``_''.
> ``-'' cannot be used for this, as it is a binary operator for
> subtraction instead.
Forgot that bit :-)
> _FPCOMPARE=`echo "${1/-/_} ${2/-/_} - p" | dc`
Ah. I don't generally use bash-isms: I end up using bash, ksh, sh on
different *IX platforms, so I tend to operate at sh level when writing
scripts. (Yes, I know this is coLm.)
Regards
I used to be bitten by that behaviour, until I discovered the "-l" option :
$ echo "1 / 3" | bc
0
$ echo "1 / 3" | bc -l
.33333333333333333333
(I've seen this on HP-UX too, so it's not just a GNU-ism)
David.
--
(david.cook at pobox.com)
(in Melbourne, Australia)
Right; my bc example should have been:
_FPCOMPARE=`echo $1 - $2 | bc -l`
>> To enter a negative number, begin the number with ``_''.
>> ``-'' cannot be used for this, as it is a binary operator for
>> subtraction instead.
>
> Forgot that bit :-)
>
>> _FPCOMPARE=`echo "${1/-/_} ${2/-/_} - p" | dc`
>
> Ah. I don't generally use bash-isms: I end up using bash, ksh, sh on
> different *IX platforms, so I tend to operate at sh level when writing
> scripts. (Yes, I know this is coLm.)
I generally do use POSIX extensions, but restrict those to
arithmetic and variable expansion. Unless I am writing a script
that really cannot be written in a Bourne, or at most POSIX,
shell, I avoid bashisms.
Use 'awk':
$ NUMBER=1; ! awk -v n=$NUMBER 'BEGIN{exit (n < .04)}' && echo Lower
$ NUMBER=0.01;! awk -v n=$NUMBER 'BEGIN{exit (n < .04)}' && echo Lower
Lower
Nice.
What is the ! for? It doesn't work without it.
Thanks,
Ian
It returns the logical NOT of the exit status value of the
following command (or last command if it precedes a pipeline).
It can be written without it:
NUMBER=0.01; awk -v n=$NUMBER 'BEGIN{exit (n < .04)}' || echo Lower
Or, less verbosely:
NUMBER=0.01; awk "BEGIN{exit ($NUMBER < .04)}" || echo Lower
Or:
NUMBER=0.01; awk "BEGIN {if ($NUMBER < .04) print \"Lower\"}"
>> $ NUMBER=1; ! awk -v n=$NUMBER 'BEGIN{exit (n < .04)}' && echo Lower
>> $ NUMBER=0.01;! awk -v n=$NUMBER 'BEGIN{exit (n < .04)}' && echo Lower
>> Lower
> What is the ! for? It doesn't work without it.
a) Apparently, "exit(v)" causes awk to return an exit status of v. In
particular, v = 1 if (n < .04) is true, or 0 if it is false.
b) In "x && y", the shell executes y if x has a successful (i.e. zero)
exit status, or skips y if x is unsuccessful (non-zero).
c) The result of a) is precisely opposite to what you want for b), so ! is
used to reverse it. Basically, b) becomes "(not x) && y", or - if
you're familiar with C syntax - "!x && y".