April 3rd, 2008 at 12:06 pm

Calculate interest rates with a shell script

If you put your cash to a bank account, you will want to know how much money you get with a certain amount at a given rate within a given period. Save the following Bash script as /usr/local/bin/loancalc (or something like that), make it executable, and you will be able to calculate the return on your investments with a single one-liner.

CODE:
  1. #!/bin/bash
  2.  
  3. function calc()
  4. {
  5.     return $(echo "scale=$2; $1" | bc)
  6. }
  7.  
  8. if [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
  9.     echo "$0 calculates the interest loan of a given amount with a given rate for a given duration."
  10.     echo "Usage: $0 AMOUNT RATE DURATION"
  11.     exit 0
  12. fi
  13.  
  14. if [ -z "$3" ]; then
  15.     echo "Please enter the amount, the rate and the duration (in this order)."
  16.     exit 1
  17. fi
  18.  
  19. AMOUNT=$1
  20. ZINS=$2
  21. DURATION=$3
  22.  
  23. echo "Investment: $AMOUNT bucks at a rate of $ZINS% for $DURATION years."
  24. echo "          Loan            Total"
  25.  
  26. for i in $(seq 1 $DURATION); do
  27.     INTERESTLOAN=$(echo "scale=10; ($AMOUNT/100)*$ZINS" | bc)
  28.     AMOUNT=$(echo "scale=10; $AMOUNT+$INTERESTLOAN" | bc)
  29.     printf "Year ${i} %8.2f " $INTERESTLOAN; printf " %14.2f\n" $AMOUNT;
  30. done
  31.  
  32. printf "Final amount: %1.2f bucks.\n" $AMOUNT

For example:

CODE:
  1. you@yourmachine ~ $ loancalc 3000 3.5 5
  2. Investment: 3000 bucks at a rate of 3.5% for 5 years.
  3.           Loan            Total
  4. Year 1   105.00         3105.00
  5. Year 2   108.68         3213.68
  6. Year 3   112.48         3326.15
  7. Year 4   116.42         3442.57
  8. Year 5   120.49         3563.06
  9. Final amount: 3563.06 bucks.

December 12th, 2007 at 12:47 pm

Playing with xgettext

xgettext is a great shell tool to create po files (i.e. Gettext translation templates). It is also able to merge existing translations with new strings. For example, to create a po template from all PHP files in a directory tree and preserve already done translations from the file my_translation-de_DE.po, enter:

CODE:
  1. mv my_translation-de_DE.po messages.po
  2. find . -type f -iname "*.php" | xgettext --keyword=__ --keyword=_e -j -f -
  3. mv messages.po my_translation-de_DE.po

Now you have a new my_translation-de_DE.po, with all the translated and the newly added strings appended to this file. (The --keywords parameter is very useful to specify your translation function(s), because if you do so, xgettext will not extract all the other strings, too.)

Unfortunately, xgettext is not able to expunge strings that are no longer existing. This behaviour is easy to explain: In many cases, you might be doing an incremental update of your translation template (i.e. you only add the strings for a subset of your files). If xgettext would expunge the translations for which no sting wasn't found in your code, you would always have to recreate the po template completely. Anyway, a little option to expunge translations that weren't found in the original, would be nice.

A little trick will at least help to determine the strings that do no longer exist: Open the po file to be merged and delete all #: lines (the regex ^#:.*$ will match them). Then merge the files as usual. In the new file, all messages without a #: marker do no longer exist. You can even modify the above code to do so automatically:

CODE:
  1. grep -v "^#:" my_translation-de_DE.po> messages.po
  2. find . -type f -iname "*.php" | xgettext --keyword=__ --keyword=_e -j -f -
  3. mv messages.po my_translation-de_DE.po

This way, you will preserve your translations, but your references are recreated, and you can easily see which strings do not exist anymore.

Update, 16.04.08: When I wrote this post, I didn't know about the msgmerge tool. Using it is much better than the grep foo above. Use it as follows:

CODE:
  1. echo ''> messages.po # xgettext needs that file, and we need it empty
  2. find . -type f -iname "*.php" | xgettext --keyword=__ --keyword=_e -j -f -
  3. msgmerge -N existing.po messages.po> new.po
  4. mv new.po existing.po
  5. rm messages.po

It looks a bit more complex, but it's the best generic solution I can provide. Note the -N parameter for msgmerge: It suppresses the fuzzy mode, which yields more confusion and extra work than anything else.