Question

I'm gonna tear my hair out: I have this script:

#!/bin/bash
if [[ $# -eq 2 ]]
then
    total=0
    IFS=' '
    while read one two; do
        total=$((total+two))
    done < $2
    echo  "Total: $total"
fi

Its supposed to add up my gas receipts I have saved in a file in this format: 3/9/13 21.76

output:

./getgas: line 9: 21.76: syntax error: invalid arithmetic operator (error token is ".76")

I read online that its possible to do float math in bash, and I found an an example script that works and it has:

function float_eval()
{
    local stat=0
    local result=0.0
    if [[ $# -gt 0 ]]; then
        result=$(echo "scale=$float_scale; $*" | bc -q 2>/dev/null)
        stat=$?
        if [[ $stat -eq 0  &&  -z "$result" ]]; then stat=1; fi
    fi
    echo $result
    return $stat
}

which looks awesome, and runs no problem

WTF is going on here. I can easily do this is C but this crap is making me mad

EDIT: I don't anything about awk. It looks promising but I don't even know how to run those one-liners you guys posted

Was it helpful?

Solution

awk '{ sum += $2 } END { printf("Total: %.2f\n", sum); }' $2

Add up column 2 (that's the $2 in the awk script) of the file named by shell script argument $2 (rife with opportunities for confusion) and print the result at the end.

I don't [know] anything about awk. It looks promising but I don't even know how to run those one-liners you guys posted.

In the context of your script:

#!/bin/bash
if [[ $# -eq 2 ]]
then
    awk '{ sum += $2 } END { printf("Total: %.2f\n", sum); }' $2
else
    echo "Usage: $0 arg1 receipts-file" >&2; exit 1
fi

Or just write it on the command line, substituting the receipts file name for the $2 after the awk command. Or leave that blank and redirect from the file. Or type the dates and values in. Or, …

Your script demands two arguments, but doesn't use the first one, which is a bit puzzling.

As noted in the comments, you could simplify that to:

#!/bin/bash
exec awk '{ sum += $2 } END { printf("Total: %.2f\n", sum) }' "$@"

Or even use the shebang to full power:

#!/usr/bin/awk -f
{ sum += $2 }
END { printf("Total: %.2f\n", sum) }

The kernel will execute awk for you, and that's the awk script written out as a two line program. Of course, if awk is in /bin/awk, then you have to fix the shebang line; the shell looks in many places for awk and will probably find it. So there are advantages to sticking with a shell script. Both these revisions simply sum what's on standard input if there are no files specified, or what is in all the files specified if there is one or more files specified on the command line.

OTHER TIPS

In bash you can only operate on integers. The example script you posted uses bc which is an arbitrary-precision calculation, included with most UNIX-like OS-es. So the script prepares an expression and pipes it to bc (the initial scale=... expression configures the number of significant digits bc should display.

A simplified example would be:

echo -e 'scale=2\n1.234+5.67\nquit' | bc

You could also use awk:

awk 'BEGIN{print 1.234+5.67}'
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top