[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.")
- Docco, Phi Debian, 2024/03/27
- Re: Docco, Andreas Kähäri, 2024/03/27
- Re: Docco,
Greg Wooledge <=
- Re: Docco, Chet Ramey, 2024/03/27