Subject: /bin/sh vs. /bin/ksh arithmetic expressions....
To: NetBSD Userlevel Technical Discussion List <tech-userlevel@NetBSD.ORG>
From: Greg A. Woods <woods@weird.com>
List: tech-userlevel
Date: 06/17/2004 15:46:25
I was "surprised" to find that /bin/sh and /bin/ksh have very different
arithmetic expression syntax.

ksh(1) says:

       Integer constants may be specified  with  arbitrary  bases
       using  the  notation  base#number, where base is a decimal
       integer specifying the base, and number is a number in the
       specified base.

However /bin/sh treats a leading zero as an indication the number is in
octal.

This lead me to the following in P1003-2001/SuSv3:

   Next, the shell shall treat this as an arithmetic expression and
   substitute the value of the expression.  The arithmetic expression
   shall be processed according to the rules given in "Arithmetic
   Precision and Operations", with the following exceptions:

     * Only signed long integer arithmetic is required.

     * Only the decimal-constant, octal-constant, and
       hexadecimal-constant constants specified in the ISO C standard,
       Section 6.4.4.1 are required to be recognized as constants.

     * The sizeof() operator and the prefix and postfix "++" and "--"
       operators are not required.

     * Selection, iteration, and jump statements are not supported.

   As an extension, the shell may recognize arithmetic expressions
   beyond those listed.  The shell may use a signed integer type with a
   rank larger than the rank of signed long.  The shell may use a
   real-floating type instead of signed long as long as it does not
   affect the results in cases where there is no overflow. If the
   expression is invalid, the expansion fails and the shell shall write
   a message to standard error indicating the failure.

So I guess ksh is the odd man out here, though The KornShell book on
p.307 agrees with the pdksh implementation in how different bases should
be specified, so in terms of standardising existing practices the good
old POSIX boys failed miserably yet again.

So, I guess it's fair to have /bin/ksh follow the real Ksh, and for
/bin/sh to follow POSIX in this case, though sh(1) is sorely lacking on
any and all pertinent details about Arithmetic Expressions (we can't
expect everyone to have a copy of SuSv3 handy!).


On the other hand /bin/sh (at least on 1.6.2_STABLE) seems to have some
kind of parsing problem with recognizing operators when there are no
non-digit tokens surrounding them:

	$ /bin/sh -c 'echo $((06170718+10000))'
	arithmetic expression: syntax error: "06170718+10000"

	$ /bin/ksh -c 'echo $((06170718+10000))'
	6180718

However so long as there is a non-digit token before the operator it's
happy without any whitespace (just operating with different base
interpretations):

	$ /bin/sh -c 'echo $(($(date +%m%d%H%M)+10000))'
	1645163

	# /bin/ksh -c 'echo $(($(date +%m%d%H%M)+10000))'
	6181534

Is this a bug?  (As far as I can tell SuSv3 is somewhat silent on the
lexical interpretation of arithmetic expressions.)  Is this still a bug
in -current?  Should I file a PR?

-- 
						Greg A. Woods

+1 416 218-0098                  VE3TCP            RoboHack <woods@robohack.ca>
Planix, Inc. <woods@planix.com>          Secrets of the Weird <woods@weird.com>