[TUHS] Arithmetic expansion in Unix shells

Brian Walden tuhs at cuzuco.com
Wed Jun 23 01:52:36 AEST 2021


even tho it was there, in-shell integer arithmetic had a few
issues before ksh86.

pre-ksh86 these had problems --

A. decimal point in a number
$ integer I
$ I=2.2

would error on the assignment, but with ksh86 $I is truncated to 2

(yes "integer" is an builtin alias to typeset -i and ksh courses at the time
instructed to use that over typset)

B. negative numbers
$ integer I
$ I=-2

here pre-86 $I would be assigned a large value like 2147483646

also ksh was not stardard until SVR4 (very late 80s) so it was found
in paths like /usr/add-on/bin/ksh or /usr/exptools/bin/ksh, or not even
there at all, you could not reliably #! ksh scripts

also with ksh86 the double paren ((...)) notation was exactly the same as
"let ..." and were completely optional if the variable was predefined as
an integer, so

$ I=0
$ ((I=I+1))

 and

$ integer I
$ I=0
$ I=I+1

are the same.

All internal integers in ksh were C longs (at least 32-bits)

where Bourne shell all vars are strings so you would need to do this --

$ I=`expr $I + 1`

But also at that time expr(1) could NOT deal with negative numbers on input,
they became strings. So

$ expr -9 + 1

is an error with "non-numeric argument", and

$ expr -11 '<' -1

returns 0, a false statement, which are hidden bugs with variables.

expr(1) was also 32-bits, as was test (i.e [ ) which could deal with
negative numbers just fine.

for arbitrarily large numbers you needed use dc(1) or bc(1). but dc(1)
also has a issue with inputing negative numbers as it uses an _ not
a - to denote a negatve number on input, but does use the - on output.

$ I=`echo _9 1 - p | dc`

is how you would do ((I=-9 - 1)) in bourne with dc
which is cumbersome if you have a variable with a neagtive number in it,
and required a "tr - _" first.

however

$ I=`echo -9 - 1 | bc`

worked just fine in bourne.


-Brian

Chet Ramey wrote:
> On 6/21/21 5:57 AM, arnold at skeeve.com wrote:
> > Arithmetic expansion dates back at least as far as ksh88.
>
> ksh had the `let' builtin from at least 1983. The ((...)) compound command
> was there by ksh-86.
>
> > Bash likely picked it up from there.
>
> Sort of, see below.
>
> > The original was only integer math and Bash remains that way (IIRC,
> > Chet can correct me if I'm wrong). ksh93 added floating point math.
>
> Yes, bash only has integer arithmetic, since it's all POSIX requires.
>
> > POSIX would have picked it up from ksh88.
>
> The $((...)) form of arithmetic expansion is something POSIX picked up
> from ksh-88, eventually. The early drafts of the standard (through 1003.2
> d9, at least), used $[...], but they eventually adopted $((...)) because
> ksh-88 had already implemented it, though it's not documented in Bolsky
> and Korn.
>
> I put $[...] into bash first (it's still there, though deprecated), then
> `let', then $((...)) after POSIX added it, and finally  `((' for
> compatibility.
>
> Chet


More information about the TUHS mailing list