0

Example file:

    25      Firstname1 Lastname1     domain1.com    planname    @1.00 USD       Monthly Active  04/24/2016      Edit
    1068    Firstname2 Lastname2     domain2.com    planname   @7.95 USD       Annually Active  05/09/2016      Edit
    3888    Firstname3 Lastname3     domain3.com    planname    @19.95 USD      Biennially Active  05/04/2016      Edit

I am extracting just the price and billing cycle and am converting the billing cycles into numerical value this way I can divide the price by the billing cycle to get a cost per month.

When using the for statement, its adding line breaks which is breaking the math.

Code:

    for i in `cat asd | cut -d "@" -f 2 | awk '{print $1, $3}' | sed 's/Monthly/\/ 1/g' | sed 's/Annually/\/ 12/g' | sed 's/Biennially/\/ 24/g' |grep -Ev 0.00` ; do echo $i | bc -l' ; done

I would prefer to be able to get 1 answer meaning all the rows get divided up then added together to get one final answer.

JCats
  • 141
  • 5
  • 13

2 Answers2

1

All those calls to cat, cut, awk, sed, grep and bc - what a waste.

This is a mis-named post, because you are not using Bash to do any calculations. The reason is that bash, unlike korn shell (ksh), does not support floating point. So you fall back to utilities like bc. Hold on though, awk supports floating point as well.

awk is a programming language in its own right. This just uses one instance of awk. I have embedded it inside a bash script because you are probably doing other stuff, but with a little adjustment it could be stand-alone with #!/bin/awk at the top:

infile='asd'

# -f - means "read the program from stdin"
# << '_END_' is a here document.  Redirect stdin from here to the label _END_
awk -f - "$infile" << '_END_'
BEGIN {
# an associative array for the billing cycles
cycles["Monthly"]    = 1
cycles["Annually"]   = 12
cycles["Biennially"] = 24
}

{
sub(/@/,"",$6)          # Remove the @ from the amount
total += $6/cycles[$8]  # divide amount by the billing cycle, add to total
}
END { print total }
_END_

Don't you think this is simpler to understand and maintain? It's also more efficient. This awk script is probably a good exercise for an awk 101 training course.

cdarke
  • 42,728
  • 8
  • 80
  • 84
0

You could do something like this: (If you are totally set on a single line)

cat asd | cut -d "@" -f 2 | awk '{print $1, $3}' | sed 's/Monthly/\/ 1/g' | sed 's/Annually/\/ 12/g' | sed 's/Biennially/\/ 24/g' | grep -Ev 0.00 | while IFS= read -r line; do echo "$line" | bc -l; done | tr '\n' '+' | sed 's/+$/\n/' | bc -l

But this would be way more clear:

tmp=$(mktemp)
cat asd | cut -d "@" -f 2 | awk '{print $1, $3}' | sed 's/Monthly/\/ 1/g' | sed 's/Annually/\/ 12/g' | sed 's/Biennially/\/ 24/g' | grep -Ev 0.00 > $tmp

tmp2=$(mktemp)
cat $tmp | while IFS= read -r line; do
  echo "$line" | bc -l >> $tmp2
done

# Actual output
cat $tmp2 | tr '\n' '+' | sed 's/+$/\n/' | bc -l
rm $tmp $tmp2
alexoneill
  • 503
  • 3
  • 13
  • Several examples of useless use of `cat`. There can be portability issues with `mktemp`. See http://stackoverflow.com/questions/2792675/how-portable-is-mktemp1 – cdarke Apr 11 '16 at 06:41