Skip to content

RPN Calculator in Bash

This Bash script implements a Reverse Polish Notation (RPN) calculator. It reads input from standard input, interprets each line as an RPN expression, and evaluates the expressions by performing arithmetic calculations.


Implementation Details

  • The script uses the IFS (Internal Field Separator) variable to define delimiters for splitting strings into words, considering space and tab characters as delimiters by default.
  • Input is read from standard input using the read command, storing each line in the expression array.
  • Empty lines are skipped, and the script moves to the next line.
  • Tokens in the expression array are processed sequentially:
  • Numbers are validated using regular expressions, and if valid, are pushed onto the stack.
  • Operators (+, -, *, /) require sufficient operands. If valid, the calculation is performed and the result is updated in the array.
  • The script relies on the bc command-line utility for performing floating-point arithmetic.
  • If the final expression array has exactly one element, it is the result. Otherwise, an error message is displayed.

The full reverse notation script

#!/usr/bin/env bash

IFS=$' \t' # Set the Internal Field Separator (IFS) to include space and tab characters
while read -r -a expression; do
        ((n = ${#expression[*]}))
        # Skip empty lines
        if [ $n -eq 0 ]; then continue; fi
        ((i = 0))
        # Process each element in the expression
        while :; do
                element=${expression[i]}
                # Check if the element is a valid number
                if [[ $element =~ ^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)$ ]]; then
                        ((++i)) # Increment the index to move to the next element
                elif [[ $element =~ ^[-+*/]$ ]]; then
                        # Check if there are enough operands to perform the operation
                        if [ $i -lt 2 ]; then break; fi
                        # Perform the calculation using the appropriate operator
                        case $element in
                        "+") expression[i - 2]=$(echo "${expression[i - 2]} + ${expression[i - 1]}" | bc) ;;          # Addition
                        "-") expression[i - 2]=$(echo "${expression[i - 2]} - ${expression[i - 1]}" | bc) ;;          # Subtraction
                        "*") expression[i - 2]=$(echo "${expression[i - 2]} * ${expression[i - 1]}" | bc) ;;          # Multiplication
                        "/") expression[i - 2]=$(echo "scale=2; ${expression[i - 2]} / ${expression[i - 1]}" | bc) ;; # Division
                        esac
                        # Remove the used operands and operator from the array
                        expression[i]=
                        ((--i)) # Decrement the index to adjust for the removed elements
                        expression[i]=
                        ((n -= 2))                      # Adjust the number of elements in the expression
                        expression=("${expression[@]}") # Compact the array by removing the empty elements
                else
                        break
                fi
                # Check if all elements have been processed
                if [ $i -eq $n ]; then break; fi
        done
        # Check if the result is valid and print it, or print an error message
        if [ $i -eq $n ] && [ $n -eq 1 ]; then
                echo "${expression}" # Output the result
        else
                echo 'error' # Output error message
        fi
done

Examples Usage

Addition

./rpn_calculator.sh
5 2 +
7

Subtraction

./rpn_calculator.sh
8 3 -
5

Multiplication

./rpn_calculator.sh
4 6 *
24

Division

./rpn_calculator.sh
10 2 /
5.00

Invalid expression

./rpn_calculator.sh
5 +
error