bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Docco


From: Greg Wooledge
Subject: Re: Docco
Date: Wed, 27 Mar 2024 07:23:33 -0400

On Wed, Mar 27, 2024 at 10:00:06AM +0100, Phi Debian wrote:
> $ man bash
> ...
> CONDITIONAL EXPRESSIONS
> ...
> 
>        -a file
>               True if file exists.
>        -e file
>               True if file exists.
> ...
> 
> 'May be' would be nice for newbies to precise which options are [ specific
> vs [[ specific for instance
> 
>        -a file
>               True if file exists ([[ only, for [ see test builtin)
> 
> This to avoid things like
> 
> $ [   -a /tmp ] && echo ok || echo nok
> ok
> $ [ ! -a /tmp ] && echo ok || echo nok
> ok
> 
> I know it is obvious, unless this is intended to force a complete
> multi-pass man read...

I wouldn't say it's "obvious" what's happening here.  The problem is
that there are two different "-a" operators, one unary, and one binary.
"help test" documents both of them:

hobbit:~$ help test | grep -- -a
      -a FILE        True if file exists.
      EXPR1 -a EXPR2 True if both expr1 AND expr2 are true.

In your first example, you are using the unary -a operator on a file:

> $ [   -a /tmp ] && echo ok || echo nok
> ok

This one returns true because there are two arguments, and the first one
is not '!', and is a "unary primary" (POSIX wording).  Therefore it uses
the unary  -a and tests for existence of the second argument as a file.

In your second example, you are using the binary -a operator:

> $ [ ! -a /tmp ] && echo ok || echo nok
> ok

Here, you have three arguments, and argument 2 is a "binary primary"
(POSIX wording again), so it's treated as if you had written this:

    [ ! ] && [ /tmp ] && echo ok || echo nok

This is simply performing two string length tests.  Both strings are
non-empty (the first is one character, and the second is four), so
the result is true.

The check for whether the first argument is '!' is not performed,
because the "$2 is a binary primary" check comes first.  This is how
POSIX documents it.

So... how do you work around this?  Well, the easiest way would be
to stop using -a entirely.  Both the unary *and* binary forms.  The
unary form can be replaced by -e, and then everything works as you
expect.  The binary form should be discarded along with "-o", and
never used.  You are much better off stringing together multiple
test or [ commands instead:

    if [ -e "$logdir" ] && [ -e "$outputdir" ]; then ...

This removes all ambiguity, and is in fact the only supported way
to write this under POSIX restrictions (">4 arguments: The results
are unspecified.")



reply via email to

[Prev in Thread] Current Thread [Next in Thread]