InfinityQuest - Programming Code Tutorials and Examples with Python, C++, Java, PHP, C#, JavaScript, Swift and more

Menu
  • Home
  • Sitemap

Python Programming Language Best Tutorials and Code Examples

Learn Python Right Now!
Home
Bash
Creating a Simple RPN Calculator in bash
Bash

Creating a Simple RPN Calculator in bash

InfinityCoder February 19, 2017

You may be able to convert binary to decimal, octal, or hex in your head but it seems that you can’t do simple arithmetic anymore and you can never find a calculator when you need one.

What to do?

Create a calculator using shell arithmetic and RPN notation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/env bash
# cookbook filename: rpncalc
#
# simple RPN command line (integer) calculator
#
# takes the arguments and computes with them
# of the form a b op
# allow the use of x instead of *
#
# error check our argument counts:
if [ \( $# -lt 3 \) -o \( $(($# % 2)) -eq 0 \) ]
then
   echo "usage: calc number number op [ number op ] ..."
   echo "use x or '*' for multiplication"
   exit 1
fi
 
ANS=$(($1 ${3//x/*} $2))
shift 3
while [ $# -gt 0 ]
do
   ANS=$((ANS ${2//x/*} $1))
   shift 2
done
echo $ANS

The idea of RPN (or postfix) style of notation puts the operands (the numbers) first, followed by the operator.

If we are using RPN, we don’t write 5 + 4 but rather 5 4 + as our expression.

If you want to multiply the result by 2, then you just put 2 * on the end, so the whole expression would be 5 4 + 2 *, which is great for computers to parse because you can go left to right and never need parentheses.

The result of any operation becomes the first operand for the next expression.
In our simple bash calculator we will allow the use of lowercase x as a substitute for the multiplication symbol since * has special meaning to the shell.

But if you escape that special meaning by writing ‘*’ or \* we want that to work, too.
How do we error check the arguments? We will consider it an error if there are less than three arguments (we need two operands and one operator, e.g., 6 3 /).

There can be more than three arguments, but in that case there will always be an odd number (since we start with three and add two more, a second operand and the next operator, and so on, always adding two more; the valid number of arguments would be 3 or 5 or 7 or 9 or …).

We check that with the expression:

1
$(($# % 2)) -eq 0

to see if the result is zero. The $(( )) says we’re doing some shell arithmetic inside.
We are using the % operator (called the remainder operator) to see if $# (which is the number of arguments) is divisible by 2 with no remainder (i.e., -eq 0).
Now that we know there are the right number of arguments, we can use them to compute the result. We write:

1
ANS=$(($1 ${3//x/*} $2))

which will compute the result and substitute the asterisk for the letter x at the same time.

When you invoke the script you give it an RPN expression on the command line, but the shell syntax for arithmetic is our normal (infix) notation.

So we can evaluate the expression inside of $(( )) but we have to switch the arguments around.
Ignoring the x-to-* substitution for the moment, you can see it is just:

1
ANS=$(($1 $3 $2))

which just moves the operator between the two operands. bash will substitute the parameters before doing the arithmetic evaluation, so if $1 is 5 and $2 is 4 and $3 is a + then after parameter substitution bash will have:

1
ANS=$((5 + 4))

and it will evaluate that and assign the result, 9, to ANS.

Done with those three arguments, we shift 3 to toss them and get the new arguments into play.

Since we’ve already checked that there are an odd number of arguments, if we have any more arguments to process, we will have at least two more (only 1 more and it would be an even number, since 3+1=4).
From that point on we loop, taking two arguments at a time.

The previous answer is the first operand, the next argument (now $1 as a result of the shift) is our second operand, and we put the operator inside $2 in between and evaluate it all much like before.

Once we are out of arguments, the answer is what we have in ANS.
One last word, about the substitution. ${2} would be how we refer to the second argument.

Though we often don’t bother with the {} and just write $2, we need themhere for the additional operations we will ask bash to perform on the argument.

We write ${2//x/*} to say that we want to replace or substitute (//) an x with (indicated by the next /) an * before returning the value of $2.

We could have written this in two steps by creating an extra variable:

1
2
OP=${2//x/*}
ANS=$((ANS OP $1))

That extra variable can be helpful as you first begin to use these features of bash, but once you are familiar with these common expressions, you’ll find yourself putting them all together on one line (even though it’ll be harder to read).
Are you wondering why we didn’t write $ANS and $OP in the expression that does the evaluation?

We don’t have to use the $ on variable names inside of $(( )) expressions, except for the positional parameters (e.g., $1, $2).

The positional parameters need it to distinguish them from regular numbers (e.g., 1, 2).

Share
Tweet
Email
Prev Article
Next Article

Related Articles

Getting Your Plurals Right in bash
You want to use a plural noun when you have …

Getting Your Plurals Right in bash

Testing for More Than One Thing in bash
What if you want to test for more than one …

Testing for More Than One Thing in bash

About The Author

InfinityCoder
InfinityCoder

Leave a Reply

Cancel reply

Recent Tutorials InfinityQuest

  • Adding New Features to bash Using Loadable Built-ins in bash
    Adding New Features to bash Using Loadable …
    June 27, 2017 0
  • Getting to the Bottom of Things in bash
    Getting to the Bottom of Things in …
    June 27, 2017 0

Recent Comments

  • fer on Turning a Dictionary into XML in Python
  • mahesh on Turning a Dictionary into XML in Python

Categories

  • Bash
  • PHP
  • Python
  • Uncategorized

InfinityQuest - Programming Code Tutorials and Examples with Python, C++, Java, PHP, C#, JavaScript, Swift and more

About Us

Start learning your desired programming language with InfinityQuest.com.

On our website you can access any tutorial that you want with video and code examples.

We are very happy and honored that InfinityQuest.com has been listed as a recommended learning website for students.

Popular Tags

binary data python CIDR convert string into datetime python create xml from dict python dictionary into xml python how to create xml with dict in Python how to write binary data in Python IP Address read binary data python tutorial string as date object python string to datetime python

Archives

  • June 2017
  • April 2017
  • February 2017
  • January 2017
  • December 2016
  • November 2016
Copyright © 2021 InfinityQuest - Programming Code Tutorials and Examples with Python, C++, Java, PHP, C#, JavaScript, Swift and more
Programming Tutorials | Sitemap