[Bug 206295] sh(1)/test(1) bug (precedence)

bugzilla-noreply at freebsd.org bugzilla-noreply at freebsd.org
Fri Jan 15 18:08:25 UTC 2016


https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=206295

            Bug ID: 206295
           Summary: sh(1)/test(1) bug (precedence)
           Product: Base System
           Version: 9.3-RELEASE
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: bin
          Assignee: freebsd-bugs at FreeBSD.org
          Reporter: nibbana at gmx.us

The following demonstrates the bug and the fix.
It appears to be a "hack" in the test(1) code
for some very peculiar exception; the cause
for this exception is unknown ...

This should be fixed regardless of what originally
caused this exception since it is obviously a stupid
and illogical hack to base system utilities (sh(1)/test(1))
that breaks their standard and normally intended usage.

> > If you have authoritative knowledge on the subject,
> > please state if this functionality is correct:
> >
> > $ [ ! "" -a "" ] && echo pass || echo fail
> > pass
> > $ [ ! 11 -a "" ] && echo pass || echo fail
> > pass
> >
> > The "-a" operator binds stronger than the "!" operator.
> > Intuition based on functionality in awk/C would suppose
> > that the "!" operator would bind stronger than the "-a"
> > operator, especially since "-a" does in fact have higher
> > precedence than the "-o" operator, as in awk/C.
> >
> > In order to make it work as "expected", it gets ugly:
> >
> > $ [ ! "" -a "" ] && echo pass || echo fail
> > pass
> > $ [ \( ! "" \) -a "" ] && echo pass || echo fail
> > fail
> >
> > $ [ ! 11 -a "" ] && echo pass || echo fail
> > pass
> > $ [ \( ! 11 \) -a "" ] && echo pass || echo fail
> > fail
> >
> > I never noticed this in 20 years, so I don't know if it always
> > worked this way, or if something changed in my upgrade from
> > 4.11 to 9.3.
>
> --
> REPLY#1
> #######
> I think that while unexpected in comparison to other languages which
> have inherited C-like operator precedence rules, this is according to
> the POSIX standard for test(1).  As the man page says:
>
>      The test grammar is inherently ambiguous.  In order to assure a degree
>      of consistency, the cases described in the IEEE Std 1003.2
>      (``POSIX.2''), section D11.2/4.62.4, standard are evaluated
>      consistently according to the rules specified in the standards
>      document.  All other cases are subject to the ambiguity in the
>      command semantics.
>
> and it notes that the ambiguous cases are those involving (), -a and -o.
>
> Your test might be more clearly expressed as:
>
> $ [ ! "" ] && [ "" ] && echo pass || echo fail
> fail
>
> (although I'd recommend the -z and -n operators for testing the
> emptiness / undefinedness or not of strings.)
>
> --
> REPLY#2
> #######
> I would never claim to be an authority, but a quick look at the test(1)
> code shows that although the comments starting line 53 suggest the
> grammar one would expect, there's a special case in main() for an
> expression of exactly four parts starting with "!". The comment on line
> 218 is relevant to your tests.
>
> 217          if (nargc == 4 && strcmp(*t_wp, "!") == 0) {
> 218       /* Things like ! "" -o x do not fit in the normal grammar. */
> 219                  --nargc;
> 220                  ++t_wp;
> 221                  res = oexpr(t_lex(*t_wp));
> 222          } else
> 223                  res = !oexpr(t_lex(*t_wp));
>
> I presume the shells use a version of this code as well. My guess would
> be that this is some sort of kludge going back to the original bourne
> shell, but someone else more knowledgeable than me will have to deal
> with that.

In regards to Reply#1, yes, I did read that previously, but that leaves
the sensibility of the cited functionality open to whatever is most
sensible.  And the current functionality does not seem sensible due
to its apparent senseless incongruity with standard functionality
in most/all other languages, in addition to making simple expressions
more lengthy/tedious/ugly than necessary.  Of course, these were just
examples to demonstrate the functionality.

In regards to Reply#2 - that sure is odd!

$ [ ! "" -a "" ] && echo pass || echo fail
pass
$ [ ! "" -a "" -a "" ] && echo pass || echo fail
fail

You hit the nail on the head!  This is terrible.
Thank you for making that insightful effort to find the real
reason for this functionality - this sure is a strange exception.

-- 
You are receiving this mail because:
You are the assignee for the bug.


More information about the freebsd-bugs mailing list