views:

752

answers:

3

I'm trying to write a bash script and I needed to do some floating point math. Basically I want to do something like this:

NUM=$(echo "scale=25;$1/10" | bc)
if [ $? -ne 0 ]
then
echo bad
fi

The problem I'm running into is $? tends to hold the output from the echo program and not the bc call. Is there a way I save the output from the bc program into a variable?

Thanks,

helixed

EDIT:

Thanks for the quick replies. Here's another way of looking at the problem. Say I modified the script a little bit so it looks like this:

#!/bin/bash
NUM=$(echo "scale=25;$1/10" | bc)
if [ $? -ne 0 ]
then
echo bad
exit
fi
echo "$NUM"

When the user inputs a normal floating point value, it works fine:

bash script.sh 1.0

output:

.1000000000000000000000000

However, when the user enters an incorrect value, the script can't recover:

bash script.sh 1.0a

output:

(standard_in) 1: parse error

What I'm trying to do is get it to exit gracefully.

Thanks again for the help,

helixed

+2  A: 

I don't see anything wrong. $NUM is supposed to hold your bc command results

see:

NUM=$(echo "scale=25;$1/10" | bc)
echo "\$? is $?"
echo "NUM is $NUM"

output

$ ./shell.sh 10
$? is 0
NUM is 1.0000000000000000000000000

another way is to use awk

NUM=$(awk -vinput="$1" 'BEGIN{printf "%.25f", input/10 }')
echo "\$? is $?"
echo "NUM is $NUM"

The other way, is to do the check of "$1" before you pass to bc. eg

shopt -s extglob
input="$1"
case "$input" in
 +([0-9.]))
     IFS="."; set -- $input
     if [ $# -ne 2 ];then
        echo "bad decimal"
     else
        NUM=$(echo "scale=25;$1/10" | bc  )
        echo "$NUM"
     fi
esac

you don't have to check for $? from bc anymore

ghostdog74
Remember that the successful echo of 'NUM is $NUM' will have overwritten the value in $? from the '$(echo ... | bc)' command.
Jonathan Leffler
yes, thanks for the correction.
ghostdog74
I clarified my post above. Thanks for the tip on awk. If I can't get bc to work, I'll have to check it out.
helixed
another way, is to sanitize your input $1 to be a decimal or number before passing to `bc`. see my edit.
ghostdog74
That's a cleaver check, but is there any way to make sure there's only one '.' character present? Thanks.
helixed
@helix, see edit
ghostdog74
Cool, that works. Thanks.
helixed
A: 

Are you after the result of calculation from bc (which you store in NUM) or the status return from the system call?

As I said you have the result of calculation in $NUM:

#bctest.sh
NUM=$(echo "scale=25;$1/10" | bc)
if [ $? -ne 0 ]
then
echo bad
fi

echo "result: ", $NUM

Test:

bash ./bctest.sh 15
result: , 1.5000000000000000000000000
stefanB
I was trying to get the status return from the system call. Sorry, I should have been more explicit.
helixed
A: 

For GNU bc, an error similar to "(standard_in) 1: syntax error" will be output on stderr. You can capture this in your variable and check for it.

#!/bin/bash
NUM=$(echo "scale=25;$1/10" | bc 2>&1)
if [[ $NUM =~ error || $? -ne 0 ]]
then
    echo bad
    exit
fi
echo "$NUM"
Dennis Williamson