Hey there!
Just this past week I stumbled on a HN comment from 2019. The commenter was fiddling with some scripts to perform some simple math directly on the (bash) terminal.
TLDR: Click here to go to the code and skip the backstory.
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 sounded interesting. I normally open a terminal and invoke Python when I need to do some simple math, and doing it directly without invoking python was appealing.
If I were to do 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:
# Let's just simulate a directory with some files
$ mkdir test
$ cd test
$ touch fname1
$ touch fname2
# Now, if we invoke the function, the '*' will be replaced with file names
$ C 4 * 5
File "<string>", line 1
print(4 fname1 fname2 5)
^
SyntaxError: invalid syntax
We might thing about disabling the expansion on our C
command. But the expansion 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 way, the alias runs set -f
and disables the expansion before the __calc
function arguments get a chance to be evaluated.
$ C 4 * 5
20
$ echo *
fname1 fname2
Ok, now lets import the Python math library…
__calc () {
python -c "from math import *; print($*)"
set +f # Re-enable wildcard expansion
}
alias C='set -f; __calc '
And let's we use the library to do some calculations:
$ C sqrt( 999 )
bash: syntax error near unexpected token `('
Well, that's not great. See, the (
character in bash will be understood as the start of a subshell and this, unlike the file name expansion, cannot be disabled.
To be honest, I have yet not found a solution for this, but I can offer you two options:
One, just 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 '
And with this we have our calculations on the shell:
$ C sqrt [ 3 + [ 3 * 4 ] / 2 ]
3.0
That's it, maybe it can be useful to you. Bye!