Ir al contenido principal

Quick math on the terminal

TLDR: Click here to go to the code and skip the backstory.

Just this week I've stumbled on a HN comment from 2019 which mentioned the commenter was fiddling with some scripts to perform some simple math directly on the (bash) terminal.

What the commenter proposed was something like this, based on the dc command (comments are mine).

$ . calc.sh  # Load functionality
$ * 4 5      # Multiply 4 and 5
20
$ / 21 3     # Divide 21 by 3
7

This was interesting, because I normally open a terminal and invoke python when I need to do some simple math. Doing it directly without invoking python sounded useful.

I would just add a simple change, some people can find Polish notation intuitive, but for this I'd rather have some more standard notation. Think something like:

$ C 4 * 5
20
$ C 21 / 3
7

You get the point, the command is named C and the arguments should feel as natural as possible.

The simplest way to do this would be to write a simple bash function that invokes the python interpreter transparently, let's say...

C () {
  python -c "print($*)"
}

But there's a problem! With this we can perform some commands, but products (*) will get expanded into file names:

$ mkdir test
$ cd test
$ touch fname1
$ touch fname2
$ C 4 * 5
  File "<string>", line 1
    print(4 fname1 fname2 5)
            ^
SyntaxError: invalid syntax

We might thing about disabling the expansion on our = command. But the expansion but this happens before our command is run, so that won't fix it.

Something that looks like a command, and can do things before it's arguments are expanded is an alias.

__calc () {
  python -c "print($*)"
  set +f  # Re-enable wildcard expansion
}

alias C='set -f; __calc '

This has better results...

$ C 4 * 5
20
$ echo *
fname1 fname2

Ok, now lets import the python math library and see what can we do with it.

__calc () {
  python -c "from math import *; print($*)"
  set +f  # Re-enable wildcard expansion
}

alias C='set -f; __calc '

Now let's we use the library to do some calculation:

$ C sqrt( 999 )
bash: syntax error near unexpected token `('

Ouch! that is not great...

To be honest, I have yet not found a solution for this, but I can offer you two options:

One is to either quote the parameters:

$ C "sqrt( 999 )"
31.606961258558215

The other is to take in the command with other charaters replacing the parens []():

Result

__calc () {
  local __calc_CMD=$(echo "$*"|tr "[]" "()")
  python -c "from math import *; print($__calc_CMD)"
  set +f  # Re-enable wildcard expansion
}

alias C='set -f; __calc '

With this we have our calculations on the shell:

$ C sqrt [ 3 + [ 3 * 4 ] / 2 ]
3.0