Arithmetic calculation in shell scripting-bash

2019-08-25 02:28发布

I have an input notepad file as shown below:

sample input file:

vegetables and rates

kg  rate    total 
Tomato  4   50  100
potato  2   60  120 
Beans   3   80  240

Overalltotal: (100+120++240) = 460

I need to multiply the column 2 and column 3 and check the total if it is right and the overall total as well. If that's not right we need to print in the same file as an error message as shown below

enter code here

sample output file:

vegetables and rates

kg  rate    vegtotal

Tomato  4   50  200
potato  2   60  120 
Beans   3   80  240

Overalltotal: (200+120++240) = 560

Error in calculations: Vegtotal for tomato is wrong: It should be 200 instead of 100 Overalltotal is wrong: It should be 560 instead of 460

Code so far:

for f in Date*.log; do
       awk 'NR>1{ a[$1]=$2*$3 }{ print }END{ printf("\n");
            for(i in a)
       { if(a[i]!=$4)
              { print i,"Error in calculations",a[i] }
            } }' "$f" > tmpfile && mv tmpfile "$f"; 

done

It calculates the total but not comparing the values. How can I compare them and print to same file?

标签: bash shell awk
2条回答
狗以群分
2楼-- · 2019-08-25 02:55

Input

akshay@db-3325:/tmp$ cat file
kg  rate    total
Tomato 4 50 100 
potato 2 60 120 
Beans 3 80 240

Output

akshay@db-3325:/tmp$ awk 'FNR>1{sum+= $2 * $3 }1;END{print "Total : "sum}' file
kg  rate    total
Tomato 4 50 100 
potato 2 60 120 
Beans 3 80 240
Total : 560

Explanation

awk '                              # call awk
    FNR>1{                         # if no of lines of current file is greater than 1, 
                                   # then , this is to skip first row
            sum+= $2 * $3          # sum total which is product of value
                                   # in column2 and column3
     }1;                           # 1 at the end does default operation, 
                                   # that is print current record ( print $0 )
                                   # if you want to skip record being printed remove "1", so that script just prints total
     END{                          # end block
            print "Total : "sum    # print sum
     }
    ' file
查看更多
爷、活的狠高调
3楼-- · 2019-08-25 03:02

Complex awk solution:

awk 'NF && NR>1 && $0!~/total:/{ 
         r=$2*$3; v=(v!="")? v"+"r : r; 
         if(r!=$4){ veg_er[$1]=r" instead of "$4 } 
         err_t+=$4; t+=r; $4=r 
     }
     $0~/total/ && err_t { 
         print $1,"("v")",$3,t; print "Error in calculations:"; 
         for(i in veg_er) { print "Veg total for "i" is wrong: it should be "veg_er[i] } 
         print "Overalltotal is wrong: It should be "t" instead of "err_t; next 
     }1' inputfile

The output:

kg  rate    total 
Tomato 4 50 200
potato 2 60 120
Beans 3 80 240

Overalltotal: (200+120+240) = 560
Error in calculations:
Veg total for Tomato is wrong: it should be 200 instead of 100
Overalltotal is wrong: It should be 560 instead of 460

Details:

  • NF && NR>1 && $0!~/total:/ - considering veg lines (excuding header and total lines)

  • r=$2*$3 - the result of product of the 2nd and 3rd fields

  • v=(v!="")? v"+"r : r - concatenating resulting product values

  • veg_er - the array containing erroneous vegs info (veg name, erroneous product value, and real product value)

  • err_t+=$4 - accumulating erroneous total value

  • t+=r - accumulating real total value

  • $0~/total/ && err_t - processing total line and error events

查看更多
登录 后发表回答