Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Simple CLI calculator based on Perl's eval()

by reisinge (Hermit)
on Mar 03, 2021 at 17:27 UTC ( [id://11129086]=CUFP: print w/replies, xml ) Need Help??

Sometimes I need to do a quick calculation. I'm too lazy to open a GUI calculator and I never remember whether it's bc or dc (not mentioning the syntax). So I placed this code into ~/bin/calc:

#!/usr/bin/perl -sT use strict; use warnings; use bignum; # Command line options... our ($h, $b, $x, $c, $l); # Help message... if ($h) { print <<'EOF'; Simple CLI calculator based on Perl's eval() calc [options] <expression> -h help -b convert expression (or its result) to binary -x convert expression (or its result) to hexadecimal -c convert expression (or its result) to character -l calculate base 2 logarithm of expression calc 149,600,000/299 792 458*1000/60 # comma or space are thousands + separator calc 2x2 + 2*2 # x is the same as * (multipli +cation) calc 'sqrt(V(3+3+3) * 3)' # V is the same as sqrt (squar +e root) calc -b 2^8 # ^ is the same as ** (exponen +tiation) calc -x $RANDOM calc -c 2**17-3030 calc -l 256 EOF exit 0; } # Allowed input characters regex... my $allowed = qr'\d\+\-\/\*\.x(sqrt)V'; # Transform input a bit... @ARGV = ( "@ARGV" =~ /[$allowed]/g ); # un-taint my $expr = "@ARGV"; $expr =~ s/\s+//g; # allow whitespace in input $expr =~ s/x/*/gi; # allow x for multiplication $expr =~ s/\^/**/g; # allow ^ for exponentiation $expr =~ s/V/sqrt/g; # allow V for square root $expr =~ s/sqrt/sqrt /g; # Do the calculation... my $res = eval "$expr"; die "Does not compute...$expr\n" unless defined $res; if ($b) { # Show result in binary... printf "%s = %b\n", $expr, $res; exit } elsif ($x) { # Show result in hex... printf "%s = %x\n", $expr, $res; exit } elsif ($c) { # Show result as character... binmode(STDOUT, ':utf8'); printf "%s = %c\n", $expr, $res; exit } if ($l) { # Calculate base 2 logarithm... $res = log($res)/log(2.0); } # Show thousands in result but not in the decimal part... my ( $before_dot, $after_dot ) = split /\./, $res; $before_dot =~ s/(\d{1,3}?)(?=(\d{3})+$)/$1 /g; printf "%s = %s.%s\n", $expr, $before_dot, $after_dot // 0;
Solve the biggest problem you can. -- Nick Hanauer

Replies are listed 'Best First'.
Re: Simple CLI calculator based on Perl's eval()
by kcott (Archbishop) on Mar 04, 2021 at 04:27 UTC

    G'day reisinge,

    "Sometimes I need to do a quick calculation. I'm too lazy to open a GUI calculator ..."

    Me, too. I have a file, .bash_functions, that I source from .bashrc, which contains this function:

    function perls () { eval "echo \`perl -T -Mstrict -Mwarnings -Mautodie=:all -E ' my \$ev = eval \"$@\"; say defined \$ev ? \"\$ev\" : \"$@\"; '\`" }

    Here's some examples. The first two show normal operation; the third shows error handling.

    $ perls 6*7 42 $ perls 196**.5 14 $ perls 196***.5 Number found where operator expected at (eval 6) line 1, near "*.5" (Missing operator before 5?) 196***.5

    Obviously, that has less functionality than ++yours; however, it has served me well for quick calculations on the command line.

    In anticipation of the question, "What does the 's' stand for?"; the answer is, "I don't remember". I've been using that function for probably a decade or more; the meaning of 's' has been lost in the mists of time. :-)

    — Ken

        G'day Rolf,

        I have a whole series of functions and aliases of the form perlX, where X is a lowercase letter. Here's a couple of examples.

        This one I use almost every day. It's been in my toolbox since the mid '90s. It probably started as a simple contraction of perl -e; then -e became -E; strict and warnings were added; and so on. The -MCarp::Always is a fairly recent addition.

        $ alias perle alias perle='perl -Mstrict -Mwarnings -Mautodie=:all -MCarp::Always -E +'

        This one's for Unicode work.

        $ alias perlu alias perlu='perl -Mstrict -Mwarnings -Mautodie=:all -Mutf8 -C -E'

        These are all for my own personal use. As I've added more over the years, some obvious letters were already taken so alternative (less obvious) ones were used. Only having to remember a single letter is easy for me and not confusing at all; in fact, it's mostly muscle memory. Remembering the historical reasoning behind the choice of a letter is far less important and, in some cases, gets forgotten.

        Addendum: It looks like you've hard-coded the "less confusing" link to https://perlmonks.org/?node_id=11133350. Following that link puts me in a logged-out (Anonymous Monk) state. Please fix by changing that to [id://11133350|less confusing].

        — Ken

Re: Simple CLI calculator based on Perl's eval()
by Fletch (Bishop) on Mar 03, 2021 at 18:50 UTC

    You could also just drop into the debugger with perl -de0 and use that. Not as nice in that you've got to prefix things with x EXPR but then again you can do anything valid perl.

    (Edit: If you're using bash or zsh for simple arithmetic you could use echo $(( EXPR )) without even involving perl; or you could just swap into your emacs window and use M-x calc . . .)

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Simple CLI calculator based on Perl's eval()
by afoken (Chancellor) on Mar 03, 2021 at 18:44 UTC
    Sometimes I need to do a quick calculation. I'm too lazy to open a GUI calculator

    I'm even lazier:

    >perl -E 'say sqrt(3*3+4*4)' 5 >

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

      I am too lazy
      Too lazy for my perl
      Too lazy ...

      % python3 >>> from math import * >>> sqrt(9**5) 243.0

      I use Python REPL for simpler arithmetic operations; lately haven't had any need to know square root.

        I use Python REPL for simpler arithmetic operations

        The perldl shell, which is part of PDL, can be handy for the same thing:
        C:\>perldl perlDL shell v1.357 PDL comes with ABSOLUTELY NO WARRANTY. For details, see the file 'COPYING' in the PDL distribution. This is free software and you are welcome to redistribute it under certain conditions, see the same file for details. ReadLines, NiceSlice, MultiLines enabled Reading PDL/default.pdl... Found docs database C:/_64/strawberry-5.26.1-PDL/perl/vendor/lib/PDL/p +dldoc.db Type 'help' for online help Type 'demo' for online demos Loaded PDL v2.018 (supports bad values) Note: AutoLoader not enabled ('use PDL::AutoLoader' recommended) pdl> p sqrt(9**5) 243 pdl>
        And no need to explicitly import anything !

        Cheers,
        Rob
Re: Simple CLI calculator based on Perl's eval()
by bliako (Monsignor) on Mar 04, 2021 at 14:18 UTC

    reisinge respect for daring one more step into Lazyness. And sharing your code.

    Here's my Lazyness with a big help from Math::Symbolic and friends:

    perl -MMath::Symbolic=parse_from_string -MMath::Symbolic::Compiler=com +pile_to_sub -e ' die "no!" unless @ARGV==1 and defined($e=$ARGV[0]) and not $e=~/^\s*$/ and defined($t=Math::Symbolic::parse_from_string($e)) and ($s) = Math::Symbolic::Compiler->compile_to_sub($t) and $s and ref($s)eq"CODE" and defined($r=$s->()) ; print "$r\n"; ' 'sin(log(2,2))'

    P.S. I still don't know how to use constants (like PI) into symbolic expressions. Anyone?

    bw, bliako

Re: Simple CLI calculator based on Perl's eval()
by shmem (Chancellor) on Mar 04, 2021 at 10:38 UTC

    Nice. Being familiar with forth and thus reverse polnish notation, I use Math::RPN with ~/bin/rpn containing

    #!/usr/bin/perl use Math::RPN;$|=1; 1 while($_="@ARGV"||<>)&&!((@s=rpn@s,split)&&$s[-1]=~/^q/i||print("@s +")&&@ARGV&&print($/))

    for ad-hoc calculations.

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: Simple CLI calculator based on Perl's eval()
by roho (Bishop) on Mar 05, 2021 at 16:20 UTC
    I've been using the following on Windows for years (I named it "pc.bat"). Note: For typing convenience I replace 'x' with '*' for multiplication and perform addition on two or more numbers by separating them with spaces. I do not enter spaces around operators ('*', '/', etc.).

    Examples: pc 2x4 (Total = 8) pc 1 2 (Total = 3)

    @echo off perl -MInteger -e "s/x/*/g for @ARGV;print qq(Total = ), eval join(qq( ++),@ARGV), qq(\n)" %*

    "It's not how hard you work, it's how much you get done."

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://11129086]
Approved by marto
Front-paged by kcott
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (6)
As of 2024-03-28 20:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found