SIGPIPE 13

Programming, automation, algorithms, macOS, and more.

Shell Calculator

They say that old habits die hard, and the following is probably an example of such.

When I was 12 I bought a Commodore 64 which OS was a BASIC interpreter. One of the commands was print, and if given an arithmic expression, it’d print the result of this expression. Since the print command was typed a lot, one could use a question mark as short-hand.

Since my computer was always on and nearby, I used it as a calculator, typing e.g. ? 7.45*39.

When I was 14 I bought an Amiga, and it was only natural to create an alias for evaluating expressions on ?.

Today I have a Mac, and recently switched to zsh. I’ve previously done a similar alias/function for tcsh and bash, so today I figured it was time to do it for zsh.

Actually turned out to be rather simple:

alias '?=bc -l <<<'

With zsh, aliases are expanded first, so when writing:

? (546-425)*34

It’ll expand to:

bc -l <<< (546-425)*34

The <<< says the next part is a here-string, which is a string that is given to the command as standard input, so this is equivalent to writing:

echo '(546-425)*34' | bc -l

Notice however that in this form, we need to quote the expression, since the parenthesis and asterisk would otherwise cause a syntax error. But with here-strings all characters are taken verbatim (which is to our advantage).

The only limitation with this solution is that we cannot have any spaces in our expression. E.g. ? 42 / 7 would fail.

There is however one thing that bothers me. If you perform e.g. ? 42/7 then it’ll output:

6.00000000000000000000

To fix that we’d need to post-process the output from bc, unfortunately the alias system in zsh doesn’t support arguments, making it impossible to put anything after our arithmetic expression.

We can however wrap bc in a function that does the post-processing and then let our alias call that function instead, and that’s what I ended up doing, so I have the following two lines in my .zshrc:

eval_helper () { bc -l|perl -pe 's/(\.[^0]+)0+$|\.0+$/$1/'; }
alias '?=eval_helper <<<'

{{ numberOfCommentsTitle }}

{{ submitComment.success }}

Error Posting Comment

{{ submitComment.error }}