Paul L. Snyder on 16 Sep 2009 22:48:07 -0700


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

Re: [PLUG] floor/ceil in bash?


On September 16, 2009, "Jason Stelzer" <jason.stelzer@gmail.com>  wrote:

> Well, to be fair....
>
> First, thanks, that's a good idea. I'll just do that.
>
> Second, I really just need to always round up the the nearest whole number.

Just?

I took another look at your code snippet.  It will indeed give you the
ceiling of "something", as long as that something is the result of
dividing two positive (or two negative) integer numbers.  This may be
sufficient for your purposes.  You could avoid using the _MY_CEIL
construct you dislike by employing command substitution as used in my
previous suggestion, at the price of spawning a subshell.

It's worth noting that bash is not giving you the floor as the result of
arithmetic operations, it is giving you the result of integer division.
This is the same as the floor only if both numbers are either positive
or negative.  If one of the numbers is negative, the result of
$(( -5 / 3 )) will be -1, not -2.

If you want to do some math in bc rather than (as I originally
assumed) just give it a floating-point number, you can make it
safe for division with a small tweak.  As it stands, if do something
like

  $ MAX=5; DIVISOR=3
  $ ceil("$MAX / $DIVISOR")
  1

bc will do the math but you'll get the wrong answer.  bc's scale
defaults to 0, so an integer is returned by the division operation
and the ceiling of an integer is itself.  Change ceil to

  function newceil () { echo "define ceil (x) {if (x<0) {return x/1} \
    else {if (scale(x)==0) {return x} else {return x/1 + 1 }}} ; \
    scale=-1; y=$1; scale=0; ceil(y)" | bc; }

and you can give it a tasty arithmetic expression:

  $ MAX=5; DIVISOR=3
  $ newceil("$MAX / $DIVISOR")
  2

Quotes are necessary to make it all one argument; you might be able to
get around this by using $* instead of $1 in the function, but I haven't
tested that, so be careful.  Even as it stands there may be weird edge
cases I haven't thought about.

Don't trust something like this with user input that hasn't been
sanitized, but that's good practice for shell scripts in general.

Paul
___________________________________________________________________________
Philadelphia Linux Users Group         --        http://www.phillylinux.org
Announcements - http://lists.phillylinux.org/mailman/listinfo/plug-announce
General Discussion  --   http://lists.phillylinux.org/mailman/listinfo/plug