Software needed: Nifty bash math tools

And when I say bash math, I do not mean being mean to math, and I do not mean math as it is done in bash. I mean math as humans do it, but on the bash command line.

I would like to see a set of bash commands that do basic math, so one can do the basic math at the command line without invoking a calculator OR sending data clumsily to a program. Such as: add, which will return the sum of whatever numbers separated by white space (or expressions that can be evaluated to a number) it gets. Similarly, divide (takes two values) and multiply (takes two values). Don’t forget squareroot. One command in this toolkit could be simply the command math that takes sequences of numbers or expressions and operators and returns the closest thing to a result possible.

Comments

  1. #1 Eric Lund
    November 6, 2009

    The expr command already does this. For instance, if I type
    > expr 1 + 1
    I get the result 2.

    It’s available in both bash and tcsh.

  2. #2 Liam
    November 6, 2009

    The thinking behind a shell is that it doesn’t “do” a lot, but calls utilities to do things. Hence bc:

    echo ‘scale=10; 2+sqrt(3)/5′ | bc
    2.3464101615

  3. #3 Greg Laden
    November 6, 2009

    Eric,

    2 + 3 – 1/4 does not equal 5. Expr says it does.

    Liam: That is a very good example of why my utility is needed!

  4. #4 Dave X
    November 6, 2009

    Try this (not-well-tested) function definition in Bash:

    $ math(){
    echo “scale 10; $*”|bc
    }

    $ math 1+2 + 1/4
    3.2500000000
    $

  5. #5 rpsms
    November 6, 2009

    bash is restricted to integer math AFAIK, so you would just need to put a wrapper around Liam’s code.

    Probably this is also why eric’s example returns 5. It’s rounding up 4.75 to an integer.

  6. #6 rpenner
    November 6, 2009

    And “bc -l” would mean for many cases you could skip the “scale=10;” part.

    bc -l loads a “math library” of function defined in bc’s own scripting language.

    Then a(1)*4 is pi. Want more digits (like 200), then you need scale=200.

    $ echo ‘scale=200;a(1)*4′ | bc -l
    3.141592653589793238462643383279502884197169399375105820974944592307\
    81640628620899862803482534211706798214808651328230664709384460955058\
    223172535940812848111745028410270193852110555964462294895493038196

  7. #7 Dave X
    November 6, 2009

    @rpenner: ooh, thst’s better.

    math(){ echo “$MATHOPTIONS;$*”|bc -l; }

    PI=`math “a(1)*4″`

    echo $PI

    math $PI*4^2

    Greg, what do you expect from ‘divide 1 3′ or ‘math 1/3’?

    Greg, what would you want this to return:

    $ divide 1 3

  8. #8 Greg Laden
    November 6, 2009

    I would expect “This number can not be computed to the final digit. This is not logical. I am melting down” and then smoke to start coming from behind the monitor.

    Or, “0.33333”

  9. #9 Dave X
    November 6, 2009

    I don’t know the linux command for smoke, but defining the above wrapper function in your .bashrc should give you some of what you seek.

  10. #10 peter
    November 6, 2009

    if you’re not a bash purist,
    function add {
    python -c “print $1 + $2
    }
    function divide {
    perl -e “print $1/$2″
    }
    etc. etc…

  11. #11 rpsms
    November 6, 2009

    operators: + – / x
    usage: foo.sh + 2 2 2 2 2 2 2
    error checking: nope

    #!/bin/bash

    set -f
    expression=$@
    math_op=$1

    expression=${expression//”${math_op}” /}

    if [ “$math_op” = “x” ]; then
    math_op=”*”
    fi

    expression=${expression// /”${math_op}”}

    echo “scale=10; ${expression}” | bc
    set +f

  12. #12 Greg Laden
    November 6, 2009

    Isn’t perl math better than bc math?

  13. #13 Jeff
    November 6, 2009

    Lifehacker just had a post on this topic: http://lifehacker.com/5396183/create-an-awesome-command-line-calculator

    The short answer: put this command in your .bashrc (or .bash_profile) file: calc(){ awk “BEGIN{ print $* }” ;}

    Then you can use: “calc 99*3/5″ to get 59.4

  14. #14 Greg Laden
    November 6, 2009

    sweet. very very sweet.

  15. #15 gruebait
    November 6, 2009

    I find Python convenient for a bunch of calculations I frequently need to do. I just put a file, mymod.py in […]/site-packages. It imports a bunch of functions from math, and includes some functions I wrote for things I often do. I just fire up Python and do a ‘from mymod import *’.

    Instant personalized math from the CLI. Of course, it’s not really bash…

  16. #16 Clark
    November 6, 2009

    I use iPython a lot. Especially as my calculator. Check it out. I have it on my jailbroken iPhone and it is fantastic. If you want iPython suped up to nearly the level of Mathematica check out Sage.

  17. #17 Ivan
    November 7, 2009
    calc() { echo $@ | tr x '*' | bc -l; }

    The -l option of bc is easier than setting the scale variable, and tr allows the use of x for multiplication.

    qsum() { sed 's/^[ \t]*//;s/[ \t].*//' | grep . | \
      tr - _ | sed '2,$s/$/+/;$s/$/p/' | dc; }

    This one adds up a column of numbers specified on stdin. It assumes that the first word on each line is a number, and trims away any other data on each line.

  18. #18 Ivan
    November 7, 2009

    Oh, and for serious computation (but still quick in-and-out from the shell), use PARI/GP. Invoke at the commandline with

    gp -q

    (-q suppresses the welcome banner). Loads faster than you can blink, and does some serious shit– number theory, numerical integration, power series, special functions– all to arbitrary precision. Documentation includes a PDF reference card so you can quickly get into it.

  19. #19 Greg Laden
    November 7, 2009

    rpenner[6]: Then I should define bc as a shortcut to bc -l -c

    Ivan, nice

    As far as bash purity goes, all of the standard scripting languages are part of bash if they take one liners. That is not impure, it is very pure as part of the bash philosophy. As long as there is a healthy range of widely used and well maintained scripting languages (which currently means sed, awk, perl, python for sure) there is no pressure to add every single bell and whistle to bash. Break it down to small problems, solve one problem at at a time, do it well.

  20. #20 Peter
    November 7, 2009

    Let’s not forget R:

    You can do one-liners like this:
    alias mult= ‘Rscript -e “prod( as.double( commandArgs( TRUE ) ) )”‘

    OR this one:
    alias calc=’Rscript -e “eval( parse( text=commandArgs( TRUE ) ) )”‘

    [note: I’ve added some spaces to the above code to help it render more suitably in browsers with large font — gtl]

  21. #21 Peter
    November 7, 2009

    @Greg
    Thanks for fixing the spacing.

    I discovered a slight problem with the version of ‘calc’ that I gave above– it can be a bit tempermental about spaces. Here’s an improved version that should fix that problem and also remove the [1] at the beginning of the output:

    $ alias calc=’Rscript -e “cat( file=stdout(), eval( parse( text=paste( commandArgs(TRUE), collapse=\”\”))))”‘

  22. #22 Ralf Muschall
    November 7, 2009

    You might try zsh, it has floats (and a somewhat strange idea what characters a word consists of, unless you clear $WORDCHARS).

Current ye@r *