The default Linux shell, bash, is an advanced command interpreter that allows a system administrator to program (or 'script') complex system administration tasks. All common program control mechanisms are supported : if-then-else statements, case statements, iterations (loops), and so on. The bash shell also has arithmetic operators (add, subtract, divide, multiply), so you can use bash scripts to do calculations. Here are some examples.
This is a classic programming exercise : Say you have a given amount of money. You put it in the bank, and receive an annual interest. This interest is added to the initial amount every year. How much money will you have in 5 years ?
a possible solution :
#!/bin/bash YEARS="5" AMOUNT="15000" RATE="2" ##interest rate in % echo "SAVINGS PLAN" echo " YEARS INTEREST TOTAL" for i in $(seq 1 1 $YEARS) ; do let INTEREST=$(( $AMOUNT * $RATE / 100 )) echo -n " $i $INTEREST " let AMOUNT=$(( $AMOUNT + $INTEREST )) echo "$AMOUNT" done # display and wait for any key (for run from GUI) read dummy;
Say a friend wants to borrow a considerable amount of money, and is willing to pay you a fair interest. You could simply calculate how much interest this amount would give you if you left it in your savings account (see previous example) and charge that to your friend. However, you'd be charging interest upon interest. Also, as your friend pays back a small amount regularly, the amount over which you calculate the interest should decrease over time. Here's an attempt to handle that programmatically. In stead of hard-coded values in the script, we've also added interactive input.
#!/bin/bash echo;echo;echo #just some whitespace echo "SILLY LOAN CALCULATOR"; echo; ## init AMOUNT="" # amount of loan RATE="" # interest rate YEARS="" # period of loan ## get input while [[ "$AMOUNT" = "" ]]; do echo -n "amount of the loan: " read AMOUNT; done while [[ "$RATE" = "" ]]; do echo -n "interest rate: " read RATE; done while [[ "$YEARS" = "" ]]; do echo -n "payback period in years: " read YEARS; done ## values for internal use INTEREST="0" SUMINTEREST="0" SALDO="$AMOUNT" let MONTHS=$(( 12 * $YEARS )) let AMOUNT_PER_YEAR=$(( $AMOUNT / $YEARS )) ## main echo "TERUGBETALING LENING" echo " #YEARS SUM INTEREST" for i in $(seq 1 1 $YEARS) ; do # calculate let INTEREST=$(( $AMOUNT_PER_YEAR * $RATE * $i / 100 )) let SUMINTEREST=$(( $SUMINTEREST + $INTEREST )) # report echo " $i $SALDO $INTEREST " # set values for next interation let SALDO=$(( $SALDO - $AMOUNT_PER_YEAR )) done # Total amount due let TOTAL=$(( $AMOUNT + $SUMINTEREST )) # Output echo; echo; echo "SOLUTIONS:" echo "Amount borrowed: $AMOUNT" echo "Period: $YEARS years ($MONTHS months)" echo "interest: $SUMINTEREST ($RATE % per year)" echo;echo; echo "solution 1 : " echo " monthly payback: $MONTHS months x $(( $AMOUNT / $MONTHS )) euro = $AMOUNT euro" echo " + interest to be paid separately : $SUMINTEREST euro" echo;echo; echo "solution 2 : " echo " total amount due (including interest) : $AMOUNT + $SUMINTEREST = $TOTAL euro" echo " monthly payback: $MONTHS maanden x $(( $TOTAL / $MONTHS )) euro = $TOTAL euro" echo;echo; # display and wait (run from GUI) read dummy;
The same Loan Calculator, but with some bells and whistles : this one allows the user to specify a maximum payback amount per month, and the lenght of the loan will be calculated accordingly. Once the lengt is established, the loan is (re-)calculated again as in the previous example.
#!/bin/bash echo;echo;echo #just some whitespace echo "SILLY LOAN CALCULATOR"; echo; ## init AMOUNT="" # amount of loan RATE="" # interest rate MAX_PER_MONTH="" # maximum payback amount per month PAYBACK="65353" # payback per month MONTHS="0" # number of months INTEREST="0" # interest amount per year SUMINTEREST="0" # cumulative interest over the years TOTAL="0" # borrowed amount + cumulative interest AMOUNT_PER_YEAR="0" ## get input while [[ "$AMOUNT" = "" ]]; do echo -n "amount of the loan: " read AMOUNT; done while [[ "$RATE" = "" ]]; do echo -n "interest rate: " read RATE; done while [[ "$MAX_PER_MONTH" = "" ]]; do echo -n "maximum payback per month: " read MAX_PER_MONTH; done ## calculate loans until PAYBACK approaches MAX_PER_MONTH let MONTHS=$(( $AMOUNT / $MAX_PER_MONTH )) while [[ "$PAYBACK" -gt "$MAX_PER_MONTH" ]]; do let MONTHS=$(( $MONTHS + 1 )) if [[ "$(( $MONTHS % 12 ))" -eq "0" ]] ; then let YEARS=$(( $MONTHS / 12 )) else let YEARS=$(( $MONTHS / 12 + 1 )) fi let AMOUNT_PER_YEAR=$(( $AMOUNT / $MONTHS / 12 )) for i in $(seq 1 1 $YEARS) ; do let INTEREST=$(( $AMOUNT_PER_YEAR * $RATE * $i / 100 )) let SUMINTEREST=$(( $SUMINTEREST + $INTEREST )) done let TOTAL=$(( $AMOUNT + $SUMINTEREST )) let PAYBACK=$(( $TOTAL / $MONTHS )) done ## recalculate a payback plan with length (in months) found previously [[ "$(( $MONTHS % 12 ))" -eq "0" ]] && \ let YEARS=$(( $MONTHS / 12 )) || \ let YEARS=$(( $MONTHS / 12 + 1 )) let AMOUNT_PER_YEAR=$(( $AMOUNT / $YEARS )) SALDO="$AMOUNT" echo;echo "LOAN PAYBACK PLAN" echo " YEARS SALDO INTEREST " for i in $(seq 1 1 $YEARS) ; do # calculate let INTEREST=$(( $AMOUNT_PER_YEAR * $RATE * $i / 100 )) let SUMINTEREST=$(( $SUMINTEREST + $INTEREST )) # report echo " $i $SALDO $INTEREST " # set values for next interation let SALDO=$(( $SALDO - $AMOUNT_PER_YEAR )) done let TOTAL=$(( $AMOUNT + $SUMINTEREST )) #output echo; echo; echo "OPLOSSING:" echo "amount: $AMOUNT euro" echo "lenght: $MONTHS months ($YEARS years)" echo "interest: $SUMINTEREST euro ($RATE % per jaar)" echo echo " total payback : $AMOUNT + $SUMINTEREST = $TOTAL euro" echo " payback: $MONTHS maanden x $(( $TOTAL / $MONTHS )) euro = $TOTAL euro" echo echo
Note that the bash shell calculates with integers. This means that real numbers (eg. the results of a division) are rounded to the lower integer. To enable decimal fractions, you might use bc, an arbitrary precision (floating point) calculator for unix shells, or apply this silly workaround.
Say you want to calculate an interest rate of 2.65 percent over an amount $AMOUNT. You could do something like
AMOUNT=10000 RATE=265 # per 10,000 - ie 2.65 % # multiply relevant values by 100 to compansate for 'increased' % let AMOUNT=$(( $AMOUNT * 100 )) let INTEREST=$(($AMOUNT * $RATE / 100 )) # in the end, divide by 100 to get original values back let AMOUNT=$(( $AMOUNT / 100 )) let INTEREST=$(($INTEREST / 100 ))
Note that this workaround makes your script more complex, and your calculations more error prone. The precision is (only) 2 decimals.