0

I've been working on a trade log reader, the log is in CSV separated ';'. The problem that arouse, is that I'm unable to multiply integer value with float value when they are saved in variables.

The short summary of this function is that it's supposed to get a unit price and a count from each trade and add it or subtract it, depending on the operation (sell or buy), 

IFS=';'
function GetOverAllProfit(){
    file=$1
    shift
    [ ! -f "$file" ] && { echo "$file file not found"; exit 99; }
    while read -r date tick oper unipri curr cnt idnt
    do
        if [ "$oper" == "sell" ];then
            profit=$((profit - unipri * cnt))
        else
            profit=$((profit + unipri * cnt))
        fi
    done < "$file"
}

this returns error

syntax error: invalid arithmetic operator (error token is ".0"), where i presume the numberin the quotes is the resedual decinal places form the original number

i've tried

test=$(echo $a $b | awk '{printf "%4.3f\n",$cnt*$unipri}'

But it doesn't work, I may be doing something wrong. Just started learning bash/shell scripting so any suggestion is appreciated.

Thanks

  • @TedLyngmo Hi, thanks, that seems to be doing it, only thing is that it's also printing it and not saving it to the variable. is there a way to change this ? – Adam Ďuriník Mar 20 '21 at 18:42
  • When using external programs you usually need `variable=$(program the math expression)` to assign it to your bash variable. – Ted Lyngmo Mar 20 '21 at 18:44
  • so i've used the 'bs <<< $profit-$unipri*$cnt' , so that ought to be the math expression, `$(bc <<< $profit-$unipri*$cnt)` is not working, have i got it wrong? – Adam Ďuriník Mar 20 '21 at 18:48
  • `bc` will print to `stdout` so you need to capture the output. `res=$(bc <<< "$profit - $unipri * $cnt")` and then `res` should contain the result. The spaces I put in the input are optional. I just like them. :-) – Ted Lyngmo Mar 20 '21 at 18:53
  • Great! Good luck! – Ted Lyngmo Mar 20 '21 at 18:56
  • 1
    Wouldn't it be easier to do the whole thing in `awk`? Try `awk -F';' '{if ($3 == "sell") {profit-=$4*$6} else {profit+=$4*$6}}; END {print profit}' "$file"` – Gordon Davisson Mar 20 '21 at 19:24
  • @GordonDavisson That does indeed seem simpler but I guess it's in the eye of the beholder. I have to struggle to do anything in a language I'm not comfortable with. Doing scripts completely in awk will come later than starting out in bash for most. – Ted Lyngmo Mar 20 '21 at 19:31
  • @GordonDavisson It looks bit scarier than what i have now, but it's a quite a lot faster, i have files with more then 10k lines and it was taking few minutes to them, this does it in an instant. only thing is that it returns values in scientific notation. is there a way to change this ? – Adam Ďuriník Mar 20 '21 at 19:44
  • @AdamĎuriník Sure, just change that final `print` to `printf "%4.3f\n",profit`. BTW, I wrote it pretty compactly to fit in a comment, but if you break it into multiple lines and indent for clarity, it'll be a lot easier to follow. If you want to make it even clearer, put `oper=$3; unipri=$4; cnt=$6;` before the `if` statement, and then use those variables in the calculation. Oh, and be aware that it's going to do everything in floating point, so if you need it rounded to e.g. the nearest penny at certain points, you'll need to add that. – Gordon Davisson Mar 20 '21 at 21:46
  • Another possible complication due to floating point: if the numbers get too big, they may not precise to the penny (and even small rounding errors accumulate, so if you're adding a lot of individual numbers, the errors could get large by the end). This isn't just a problem with `awk`, but with pretty much everything that uses floating point math. There's some discussion [here](https://www.gnu.org/software/gawk/manual/html_node/Floating-point-summary.html) about this specifically for GNU `awk`. – Gordon Davisson Mar 20 '21 at 22:01

0 Answers0