Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I have a file with debit credit and withdrawal transactions. I need a bash script that records the balance after every transaction. So file is like this:

D:11/02/12:1000.50
C:11/03/12:300
W:11/05/12:95.50
D:11/10/12:125
C:11/20/12:265.50

where D = debit, C = credit, and W = withdrawal

The output needs to be like this:

11/02/12 1000.50
11/03/12 700.50
11/05/12 605.00

and so on. I have done it in awk and but cannot figure that out how to write in bash. Any advice or sample would be greatly appreciated.

share|improve this question
1  
bash doesn't do floating point math. Use awk. –  jordanm Apr 3 '13 at 1:19
1  
If you already have an awk solution, why do you want a Bash solution? –  l0b0 Apr 3 '13 at 8:36
add comment

2 Answers

Keep it simple and smart

#!/usr/bin/env bash
D_amt=0

[[ $# -eq 0 ]] && { echo -e "Usage\n\t $0 input_file"; exit 1; }

while IFS=':' read type Date amt
do
        case $type in
                D)      D_amt=$( echo $amt + $D_amt | bc ) 
                        echo $Date $D_amt && continue ;;

                C|W)    D_amt=$( echo $D_amt - $amt| bc) 
                        echo $Date $D_amt && continue ;;
        esac

done <$1
share|improve this answer
    
+1 Nit: No need for semicolon at line 2. –  l0b0 Apr 3 '13 at 8:41
    
@l0b0 thanks , I have removed that semicolon –  Rahul Patil Apr 3 '13 at 8:54
    
Thank you Rahul, this is what i was looking for. –  user2212862 Apr 3 '13 at 18:19
    
@user36368 So Please Mark this answer as correct –  Rahul Patil Apr 3 '13 at 18:21
add comment

First the question should be answered whether it makes sense to do that in bash. I really doubt that; the more as there seems to be a working solution. Where is awk unavailable but bash reliably available? Is this homework...?

But on how this can be done: This is not really floating point math but fixed point math with two digits after-point precision. So just shift the numbers by two digits, do the math and shift the result again:

shift_100_left () {
  local input output beforep afterp
  input="$1"
  if [ "$input" = "${input//./_}" ]; then
    # no . in it
    output="${input}00"
  else
    beforep="${input%.*}"
    afterp="${input#*.}"
    output="${beforep}${afterp}"
  fi
  output=${output#0}
  output=${output#0}
  echo "$output"
}
shift_100_left 100
shift_100_left 123.75

shift_100_right () {
  local input output beforep afterp length
  input="$1"
  length=${#input}
  if [ 1 -eq "$length" ]; then
    output=0.0${input}
  elif [ 2 -eq "$length" ]; then
    output=0.${input}
  else
    beforep="${input%??}"
    afterp="${input:$((length-2))}"
    output="${beforep}.${afterp}"
  fi
  echo "$output"
}
shift_100_right 1
shift_100_right 12375

This asserts that all numbers look like either xxx or yyy.yy but never like e.g. zzz.z.

share|improve this answer
    
seems too complicated !!! :D –  Rahul Patil Apr 3 '13 at 6:03
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.