[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Recomended tutoial(s) on doing arithmetic in Bash scripts



-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Sun, Mar 05, 2017 at 09:42:16AM -0600, Richard Owlett wrote:
> I'm interested in "expr" and "bc".
> The man pages lack reasonable examples.
> The tutorial/HOWTO pages confuse the issue with fancy page layouts
> and/or code samples showing how impressive the author can make the
> script's output.

Hm. Neither expr nor bc are bash, they are "external" binaries. If you
want to do arithmetic in bash, there's $((...)):

  tomas@rasputin:~$ echo $(( (3+4)/3 ))
  2

As you see, this does integer arithmetic. There's not much to it, the
usuall stuff (more or less known from C, like pre/post increment, negation,
bitwise and/or/xor... see the section "ARITHMETIC EVALUATION" in the
bash manual.

Expr and bc can do more -- but you've to take into account that they
are external programs and thus give their response on stdout: you
have to "catch" it somehow to make use of it. The `...` or the more
modern and highly recommended $(...) come in:

  tomas@rasputin:~$ foo=$(expr 3 + 4)
  tomas@rasputin:~$ echo $foo
  7

Note that expr can also only do integers. I don't know whether expr
brings anything to the table beyond portability. If you stick to bash
(or dash, or...) it seems better to keep to the builtin $((...))

If you need floating point numbers, bc (or dc) are your next stops.

Perhaps you start with a couple of small examples on what you want
to achieve, post them here and we take them as riddles :-)

Here's a little example with dc, to get your appetite going. As you
might know, I'm a Luddite and have no desktop environment. As a laptop
user, I'm still interested on my battery's status: my laptop just
quits pretty abruptly when empty, putting the excellent ext4 file
system to test. For that, I've a small xterm which displays the
battery fill status (which I want as a fraction of 1, to five
significant digits, so I can see it's moving). The repeating is
done outside the program, with "watch" -- invoked from my WM.

Here's the shell snippet. The dc magic (dividing the battery's
current status, called NOW, by the FULL status) is done at
the last line:

  #!/bin/bash
  # Notes:
  # for colors:
  # tput setaf 1 ; tput bold ; echo -n 123 ; tput setaf 7 ; tput sgr0 ; echo 456
  # cf tput(1) terminfo(5)
  # do continuous mode with watch -c, possibly t

  BAT='/sys/class/power_supply/BAT0'
  AC='/sys/class/power_supply/ADP1'
  FULL=$(cat $BAT/energy_full)
  NOW=$(cat $BAT/energy_now)
  case $(cat $AC/online) in
    0) online="BAT" ;;
    1) online="AC " ;;
    *) online="???" ;;
  esac
  echo -ne "$online " ; dc -e "5k $NOW $FULL / p"

The $online variable tells me whether I'm on AC or BATtery, for the dc line it's
"5k" to set the five significant digits, then $NOW $FULL and the division "/"
(note that dc is a stack calculator [1]), note that the expansion of $NOW, etc.
is done by the shell.

If you wanted to catch the value instead of printing it right away, you would
do $fill=$(dc -e "5k $NOW $FULL / p")

With bc it'd be similar; I never wrapped my head around bc's syntax, since
dc has served me so well, but given enough motivation I don't think it's
too hard.

The script's comments hint at the next steps: COLORZ ;-)

Enjoy

[1] Like "Foot in yourself shoot.": look under Forth here:
    http://www.thealmightyguru.com/Humor/Docs/ShootYourselfInTheFoot.html

- -- tomás
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)

iEYEARECAAYFAli8PA0ACgkQBcgs9XrR2kYGPACfab6u+HPGQbzcvEnfoCAbwjjK
46cAnR9AlDZzX0GrEAtSHwRcmL+syaKE
=LElz
-----END PGP SIGNATURE-----


Reply to: