sh man page ....

William A. Mahaffey III wam at hiwaay.net
Sun Oct 12 11:49:46 UTC 2014


On 10/12/14 05:34, Ian Smith wrote:
> Re: freebsd-questions Digest, Vol 540, Issue 6, Message: 7
> On Fri, 10 Oct 2014 10:41:49 -0500 "William A. Mahaffey III" <wam at hiwaay.net> wrote:
>   > On 10/10/14 10:30, Michael Sierchio wrote:
>   > > On Fri, Oct 10, 2014 at 8:30 AM, William A. Mahaffey III <wam at hiwaay.net> wrote:
>   > >
>   > >> .....I had a bunch of shell scripts written to use Linux
>   > >> sh, which was in fact bash, which means it had a superset of the arithmetic
>   > >> operators that traditional sh had. When I use these scripts under sh under
>   > >> FBSD 9.3, they largely work, though there are some minor differences (empty
>   > >> strings evaluate to zero (0) under bash, error under sh). The man page for
>   > >> sh doesn't reflect some of these compatibilities/incompatibilities,
>   > > Nor should it. The Bourne Shell is the Bourne Shell, is adequately
>   > > documented by the man page, and warnings about incompatibility are the
>   > > responsibility of those who foist off bash as sh.
>   > >
>   > > You're blaming your own bad habit on others. :-)
>
>   > Well !!!! The sh man page is mute on the fact that an empty string is an
>   > error in arithmetic or logical evaluations, which is an omission
>   > irrespective of what bash does :-).
>
> No, sh(1) sayeth regarding $((...)), removing some whitespace:
>
>       The allowed expressions are a subset of C expressions, summarized below.
>             Values     All values are of type intmax_t.
>             Constants  Decimal, octal (starting with 0) and hexadecimal (start-
>                        ing with 0x) integer constants.
>             Variables  Shell variables can be read and written and contain
>                        integer constants.
>             Unary operators
>                        ! ~ + -
>             Binary operators
>                        * / % + - << >> < <= > >= == != & ^ | && ||
>             Assignment operators
>                        = += -= *= /= %= <<= >>= &= ^= |=
>             Conditional operator
>                        ? :
>       The result of the expression is substituted in decimal.
>
> Now unary operations require a single value; binary operations, two.
>
> Undefined variables resolve to "", so expressions become invalid where
> one (for unary) or for binary, either|both arguments are null|undefined.
>
>   > I presume that converting Linux users to FBSD users is an agenda item
>   > here (maybe my error),
>
> Not really; sh(1) is the standard, and we're not chasing 'converts' like
> it were some kind of religion - clearly there's more than enough of that
> in the world!  bash claims to be sh compatible and I've always taken it
> at its word by using nothing but sh syntax in bash scripts on Debian :)
>
>   > thus suitably complete man pages should be an important goal, I would
>   > think. I didn't think converting from Linux to FBSD was/is a bad
>   > habit ;-) ....
>
> Noone would argue that completeness is a goal, and while mentioning that
> sh DOES NOT convert undefined (or null) variables to 0 - which is pretty
> weird - is therefore unnecessary, this brings up one thing that should
> be mentioned, and I'll do so below in response to RW's post.
>
> bash(1) specifically states: "A shell variable that is null or unset
> evaluates to 0 when referenced by name without using the parameter
> expansion syntax." and later "A null value evaluates to 0", but it goes
> without saying - because it's not said - that in sh(1) that is not so.
>
> I'll also point out that bash(1) is 5463 lines (on 9.3) and sh(1) is
> 1631 lines, or just less than 30% the size.  From bash(1):
>
> BUGS
>         It's too big and too slow.
>
>         There are some subtle differences between bash and traditional versions
>         of sh, mostly because of the POSIX specification.
>
> 'subtle differences' hardly cuts it, and to reverse the onus, bash(1)
> doesn't point out ITS incompatible foibles - like this very 0 thing.
>
> In Message: 12
> On Fri, 10 Oct 2014 18:38:14 +0100 RW <rwmaillists at googlemail.com> wrote::
>   > On Fri, 10 Oct 2014 10:30:19 -0500
>   > William A. Mahaffey III wrote:
> [..]
>   > > I have a FBSD 9.3 desktop that supplanted a Linux FC14 desktop used
>   > > for web access, some light development, & other day-to-day tasks
>   > > (i.e. my daily driver, so to speak). I had a bunch of shell scripts
>   > > written to use Linux sh, which was in fact bash, which means it had a
>   > > superset of the arithmetic operators that traditional sh had. When I
>   > > use these scripts under sh under FBSD 9.3, they largely work, though
>   > > there are some minor differences (empty strings evaluate to zero (0)
>   > > under bash, error under sh).
>   >
>   > Can you give an example?
>   >
>   > $ sh
>   > $ echo $((1+c))
>   > 1
>
> Now this is strange.  bash(1) points out that "Within an expression,
> shell variables may also be referenced by name without using the
> parameter expansion syntax".  That this works in sh(1) does appear to be
> undocumented, though I've quite often seen it used, and wondered.  And
> what's worse, when you DO use the full form ($variable), it fails!
>
> % sh -c 'echo $(( 1+c ))'
> 1
> % sh -c 'echo $(( 1-c ))'
> 1
> % sh -c 'echo $(( 1/c ))'
> arithmetic expression: division by zero: " 1/c "
> % sh -c 'echo $(( 1|c ))'
> 1
> % sh -c 'echo $(( 1&c ))'
> 0
>
> But:
>
> % sh -c 'echo $(( 1 & $c ))'
> arithmetic expression: expecting primary: " 1 &  "
> % sh -c 'echo $(( 1 ^ $c ))'
> arithmetic expression: expecting primary: " 1 ^  "
> % sh -c 'echo $(( 1 + $c ))'
> arithmetic expression: expecting primary: " 1 +  "
> % sh -c 'echo $(( 1 + c ))'
> 1
>
> As far as I can tell, neither of these behaviours are documented, though
> I may have missed something; sh(1) is generally both terse and precise.
>
> And further [just _sometimes_ quoting from digests can be useful :-]
>
>   > Straight out of the script which is failing. Under linux, if I call the
>   > script w/ no '-s #' option, the variable 'slept' is not set, & linux (or
>   > more accurately linux bash) evaluates that to the value oif zero (0).
>   >
>   >
>   > [wam at kabini1, ~, 7:07:22pm] 386 % sh
>   > $ if [ 0 -lt $(($slept)) ] ; then echo -n "$cmd: sleeping $slept secs
>   > ...." ; sleep $(($slept)) ; echo " done." ; fi
>   > arithmetic expression: expecting primary: ""
>   > [wam at kabini1, ~, 7:07:45pm] 387 %
>
> So just precede that and similar instances with:
>
>    [ -z "$slept" ] && slept=0	# or [ ! "$slept" ] ...
>
> Either way, quotes are required around potentially undef/null variables
> in test aka [, and never hurt.
>
> And though it's only what I read in sh(1), you should be able to use the
> ${parameter:=word} form to assign a default value if unset or null:
>
> 	if [ 0 -lt ${slept:=0} ; ...	# no need for the $((..)) form
>
> cheers, Ian
>


100% correct on all facts, & I agree 100% w/ everything you say/said 
.... including the point that some of the behaviors are undocumented, & 
possibly unexpected (my assessment) .... That's all I was (lamely) 
asking for, a bit more detail in the sh man page :-) .... The references 
to bash by me were for context *only* .... Thx for the detailed & 
illuminating reply.


-- 

	William A. Mahaffey III

  ----------------------------------------------------------------------

	"The M1 Garand is without doubt the finest implement of war
	 ever devised by man."
                            -- Gen. George S. Patton Jr.



More information about the freebsd-questions mailing list