Skip to content

Instantly share code, notes, and snippets.

@VladSavitsky
Last active December 13, 2025 17:17
Show Gist options
  • Select an option

  • Save VladSavitsky/e01316c231d15634a9d02e30b74d0dc8 to your computer and use it in GitHub Desktop.

Select an option

Save VladSavitsky/e01316c231d15634a9d02e30b74d0dc8 to your computer and use it in GitHub Desktop.
Bash Calculator
# Bash Calculator using command_not_found_handle
# Version: 7.5.0
# Uses = as calculator prefix: =2+2, ="(2+3)*4", =[2+3]*4, ?sqrt(16)
# For division, use space: = 10/3
# Or quote: ='10/3'
calc_internal() {
local expression="$*"
# If expression is empty, show usage
if [[ -z "$expression" ]]; then
echo "Calculator: =expression"
echo "Examples: =2+2, =\"(2+3)*4\", =\"sqrt(16)\", =.5*2"
echo " =2+2, =\"(2+3)*4\" (for simple expressions)"
return 1
fi
# Convert brackets to parentheses
expression="${expression//\[/(}"
expression="${expression//\]/)}"
# Add leading zero to decimals starting with .
if [[ "$expression" =~ ^-?\. ]]; then
if [[ "$expression" =~ ^-\. ]]; then
expression="-0.${expression:2}"
else
expression="0.${expression:1}"
fi
fi
# Fix other decimal cases (after operators)
expression=$(echo "$expression" | sed -E '
s/\(\./(0./g;
s/\+\./+0./g;
s/-\./-0./g;
s/\*\./*0./g;
s/\/\./\/0./g;
')
# Calculate using bc
local result
result=$(bc -l <<< "scale=3; $expression" 2>&1)
# Check for bc errors
if [[ "$result" =~ ^\(standard_in\) ]] ||
[[ "$result" =~ [Ee]rror|[Dd]ivide.*[Zz]ero|[Ss]yntax ]]; then
echo "Math error: Invalid expression" >&2
return 1
fi
# Clean result: remove trailing zeros and decimal point
result=$(echo "$result" | sed -E '
s/\.[0]+$//
s/\.$//
s/^[[:space:]]+//
s/[[:space:]]+$//
')
[[ -z "$result" ]] && result="0"
[[ "$result" == "-" ]] && result="0"
echo "$result"
}
# This hook allows to use '=expr' (no space) beside '= expr' (with space).
command_not_found_handle() {
# Check if command is "=".
if [[ "$*" =~ ^= ]]; then
# Remove spaces and "=".
expression=$(echo "$@" | sed 's/ //g' | sed 's/=//g');
calc_internal "$expression"
return $?
fi
echo "bash: $*: command not found" >&2
return 127
}
export -f command_not_found_handle 2>/dev/null || true
# Test function
test_bash_calc() {
echo "Testing Bash Calculator - Version 7.5.0"
echo "=================================================="
echo ""
# Store original function
local original_handle=$(declare -f command_not_found_handle)
# Temporarily unset to avoid recursion
unset -f command_not_found_handle 2>/dev/null
echo "Test cases (use space after =):"
echo " =2+2: $(calc_internal '2+2')"
echo " =(2+2): $(calc_internal '(2+2)')"
echo " =(2+3)*4: $(calc_internal '(2+3)*4')"
echo " =[2+3]*4: $(calc_internal '[2+3]*4')"
echo " =10/3: $(calc_internal '10/3')"
echo " =.5*2: $(calc_internal '.5*2')"
echo " =-.5*2: $(calc_internal '-.5*2')"
echo " =sqrt(16): $(calc_internal 'sqrt(16)')"
echo " =2*3*4: $(calc_internal '2*3*4')"
echo " =(5.5+2.3)*2: $(calc_internal '(5.5+2.3)*2')"
echo " =2^8: $(calc_internal '2^8')"
echo " =4*a(1): $(calc_internal '4*a(1)')"
echo " =s(0): $(calc_internal 's(0)')"
echo " =2++3: $(calc_internal '2++3')"
echo " =10/0: $(calc_internal '10/0')"
echo " =: $(calc_internal '')"
echo ""
echo "Simple expressions (no space, no /):"
echo " =2+2: $(calc_internal '2+2')"
echo " =2*3: $(calc_internal '2*3')"
# Restore original function
eval "$original_handle"
export -f command_not_found_handle 2>/dev/null || true
echo "=================================================="
echo "Usage: =expr"
echo "Test complete."
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment