October 09, 2013

A bashism a week: maths

You've probably already done some basic maths in shell scripts, but do you know what else you can actually do?

Pick at least 4 operations that you can do in bashisms-free shell scripts:

$((n+1))
$((n>8))
$((n^4))
$((--n))
$((n*=5))
$((n++))
$((n==1?2:3))

The POSIX:2001 standard defines the arithmetic expansion requirements, which leads us to selecting all of the above operations except two:

$((--n))
$((n++))

"--" and "++" are not required to be implemented, and in some cases they may lead to unexpected results, such as the following:


$ bash -c 'n=1; echo $((++n))'
2
$ dash -c 'n=1; echo $((++n))'
1


Remember, if you rely on any non-standard behaviour or feature make sure you document it and, if feasible, check for it at run-time.

3 comments:

  1. Additional fun:

    POSIX says to use the host’s “long” C type. This means that $((2147483647+1)) is 2147483648 on a 64-bit (or 36-bit) system and Undefined Behaviour on a 32-bit (or 31-bit) system.

    ISO C “Undefined Behaviour” (yes, capitalised) is pretty bad. The C compiler is allowed to compile the C source code of the shell in a way so that “echo $((2147483647+1))” equals “rm -rf ~ /”, no kidding.

    mksh is saner, but incompatible with POSIX there, since it behaves the same across *all* platforms: $((2147483647+1)) is -2147483648 on mksh, everywhere (defined signed 32-bit wraparound). If you need POSIX behaviour with mksh, use the “lksh” binary shipped as part of the Debian package; it’s also used for /bin/sh in jessie/sid if you choose to use mksh instead of GNU bash or dash. (mksh also supports more stuff than POSIX, like unsigned arithmetics, rotation left/right, etc.)

    Additionally, POSIX shell arithmetics are a very recent feature and thus not ubiquitous, even on POSIX conformant systems (that conform to older versions of the spec)…

    As usual: check and document what you use. If you use shell-specific things, a shebang like #!/bin/mksh does not go amiss. I personally would rather keep my shell portable than my shell scripts…

    ReplyDelete
  2. The 2001 POSIX standard was superseded long ago by the 2008 edition. You can get access via http://www.unix.org/online.html

    @mirabilos POSIX shell arithmetic is not a recent requirement; it was in the original 1992 POSIX.2 shell and utilities standard.

    ReplyDelete
    Replies
    1. Sure, there is a more recent version of POSIX but it is a specification that is not really followed by the common shell implementations.

      Delete