On Mon, 11 Jan 2010 13:13:44 -0800 Philip Guenther <guent...@gmail.com>
wrote:

> On Mon, Jan 11, 2010 at 1:01 AM, J.C. Roberts
> <list-...@designtools.org> wrote:
> > Below is a "test case" ksh shell script to show examples of very
> > minor omissions in the ksh(1) man page regarding testing for zero
> > length and non-zero length. A patch for ksh.1 is below.
> >
> > In the script, you'll need to manually fix the assignment of $foo
> > for test set #2, since sending a raw null through email is a major
> > pain. I have it set below as text '^@' but you'll need to replace
> > it with a real null (CTRL-V CTRL-@).
>
> NULs are always silently dropped from strings by the shell, so test
> this part of your script duplicates the part where foo is the empty
> string.
>

Ah, good to know. Thanks. The reason I went out of my way to
specifically test NULL is due to the wording in the standard.

# http://www.opengroup.org/onlinepubs/9699919799/utilities/test.html
#
# string
#     True if the string string is not the null string; otherwise, false

The wording for the ksh(1) man page says ``[ string ]'' tests for
non-zero length, so this gets into how NULL is defined... --until one
learns they've been stripped. ;-)

>
> > Some of the notes on the failures are very generous since the
> > current man page does mention some of the caveats but they are
> > mentioned in relation to comparison rather than length tests.
> ...
> > @@ -761,6 +761,8 @@
> >  .No \&[ Ar str No \&]
> >  use
> >  .No \&[[ -n Ar str No \&]] .
> > +Similarly, testing for zero length should use
> > +.No \&[[ -z Ar str No \&]] .
>
> Given the context, this seems unnecessary.  Currently it reads:
>                    o   The single argument form of test, which tests
> if the argument has a non-zero length, is not valid; explicit
>                        operators must always be used e.g. instead of
> [ str ] use [[ -n str ]].
>
> So, the test for "not zero length" that works with [...] but not
> [[...]] is [ ! str ]
>
> ...which can be translated using the rule already documented to get
>     [[ ! -n str ]]
>

Agreed. I also thought the above addition was was over-kill.

> > +.Pp
> > +Additionally, testing for zero length with
> > +.Dq if \&[ -z $foo \&]
> > +, or testing for non-zero length with either
> > +.Dq if \&[ -n $foo \&]
> > +, or
> > +.Dq if \&[ $foo \&]
> > +can also fail if parameter
> > +.Dq foo
> > +is
> > +.Dv NULL
> > +, or unset, or contains spaces (i.e.\&
> ...
>
> (Two nits with your manpage source:
> 1) Always start sentences at the beginning of a line,
> 2) Commas and periods should be at the end of the line, albeit
> *preceeded* with a space if the line has a formatting macro.  For
> example: .Dv NULL ,
> )
>

Thanks.

>
> I'm not entirely convinced this change should be made, in part because
> it's too narrow.  Problems with arguments to 'test' that are empty or
> contain whitespace is not restricted to -z and -n and can just as well
> hit the file tests.  Why stop there?  Programs other than 'test' are
> affected too!  And don't forget to pass '--' to programs to stop
> option parsing when the first positional argument is from a variable.
> And use arrays when you need to store multiple values that may contain
> whitespace.  And...
>

Yep. We'd have an endless man page.

> Then again, 'test' does seem to be the place where people first slam
> into this.  <mumble>
>

I resemble that remark. :-)

> (As a side-note, both the existing "Note" and your proposed addition
> are wrong about the unquoted constructs having problems when the
> variable's value is '!' or '-n'.  It's only if it's unset, empty, or
> contains characters from $IFS that a problem occurs.  Some other OSes
> (*cough* Solaris *cough*) have versions of /bin/sh that can choke on
> those, but OpenBSD's follows the rules there.)
>

On OpenBSD, with ``test ...'' and ``[...]'' the behavior of unary
operators stored within an operand makes sense, but only if you think
it through completely to realize the field separation of operand
strings exists to *ENABLE* you to stuff other operators or operands
into the test. On the other hand, if you don't think it through
completely, even OpenBSD will fail to follow the principal of least
surprise (but it's your fault) when an operand string contains an unary
operator followed by an IFS. --Just another example supporting your
statement below about adding a, "Quote your arguments!" line to the ksh
and sh man pages.

Perhaps a more accurate description like, "unary followed by IFS" would
be better?

I'm still trying to fully understand the behavior of strings containing
a newline <sigh> and I need to poke at it a bit more, but I think having
at least some mention of behavior of tests when operands contain a
newline is an improvement.

>
> > +If you are not intentionally trying to evaluate multiple elements
> > in a list, +you can avoid these caveats if you use
> > +.Dq if \&[\&[ -z $foo \&]\&]
> > +for testing zero length, and use
> > +.Dq if \&[\&[ -n $foo \&]\&]
> > +for testing non-zero length. As noted above, the use of
> > +.Dq if \&[\&[ $foo \&]\&]
> > +is not valid, so you'll need to use the
> > +.Sq Fl n
> > +operator.
>
> While directing people to use [[...]] might be okay for the ksh(1)
> manpage, it won't fly for the sh(1) manpage.  Simply saying "quote
> your arguments!" on both would be simpler.
>

Excellent Point!

The more provocative question is, "Why would you want field splitting
of operands in the [...] tests?"

Yes, I know the field splitting exists so you can feed various operators
and operands into the test, but I have a hunch the [[...]] syntax was
added to ksh specifically because someone noticed the field splitting
stuff typically does more harm than good if you're not thinking it
through. Of course, using the ksh [[...]] feature makes scripts less
portable between shells, so quoting operands is a better answer.

Do you think the addition of the [[...]] syntax in ksh was due to
misunderstanding of field splitting (failure to quote), prevention of
less than easy to understand syntax like:

        ``[ -o foo -o -o !foo ]''    # From the ksh man page.

and similar?

I'll try to cook up a better diff tomorrow in light of what you said
above.

Philip (and also kili@), thanks for your help over the last couple weeks
with the ksh stuff. I've been trying to find at least a rough answer to
the impossible question of, "What makes a shell good?"

--
J.C. Roberts

Reply via email to