[Top][All Lists]

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

Re: Possible bug in bash

From: Robert Elz
Subject: Re: Possible bug in bash
Date: Sat, 14 May 2022 13:30:22 +0700

    Date:        Fri, 13 May 2022 22:36:56 -0400
    From:        "Dale R. Worley" <worley@alum.mit.edu>
    Message-ID:  <87ilq8hmbb.fsf@hobgoblin.ariadne.com>

  | Reading your message, I believe that the rule can be stated as follows,
  | and I'd thank you to check it:


  | && and || have the same precedence, and they both "associate left".

That is correct, I believe ... I sometimes have trouble wrapping
my head around formal mathematical definitions.   But if you are
going to state it that way, you should probably also add that
short circuit evaluation is required, that is, as binary operators,
the RHS is never evaluated if the result is known from the LHS.
(This is not just an optimisation, it is a requirement.)

  | So for example

A better example might be, that for any pipelines a b c d
and where X Y and Z each represents one of the control
operators && or || in any combination
        a X b Y c Z d
is equiv to:
        { { a X b; } Y c; } Z d

And just as a hint, far and away the best/safest way to make
use of these operators is when only one of them is used
(any number of times) in one and-or list.  So:

        a && b && c && d && e && ...

causes a b c d e ... to be executed, in sequence, until one of them
"fails" (that is, exits with a status that is not zero), after which
none of the rest is executed (or evaluated at all).  The exit status
of the list is (as always in and-or lists) that of the last command
executed, so is 0 here only if every command was executed, and all
exited with status 0.   And:

        a || b || c || d || e || ...

causes a b c d e ... to be executed, in sequence, until one of them
"succeeds" (exits with status 0), after which none of the rest is
executed (or evaluated).   The exit status of the list works the
same way, but here will be 0 unless every command in the list
was executed with non-zero status returned every time.

The idiom
        command || :
is how one says "I don't care about the exit status of command".

Mixing && and || in the same and-or list takes very careful
thought, even very experienced sh programmers mess that up
more often than you'd imagine.  Much better to use the equiv
form, with the explicit grouping, the:
        a X b Y c Z d
form is one and-or list, and if X Y and Z are not all the
same, will often, if you are not very careful, have unanticipated
results.  Write it as:
        { { a X b; } Y c; } Z d
and now there are 3 independant (binary) and-or lists, which is
much easier to reason about.  (It is reasonable to expand any of
those 3 and-or lists to more terms, provided each makes use of only
one of the two possible operators, in the innermost, every operator
is X, etc.)


Bonus extra: A common error is to end a function with something like:
        $verbose && echo function finished

That is almost always wrong, as it causes the function to return
non-zero status if verbose=false.  That is, while you are debugging
the script, with verbose=true it all works as intended (perhaps add
"eventually" there) but as soon as you set verbose=false, things change.
If written as the seemingly equivalent:
        if $verbose; then echo function finished; fi
we do not get that issue, the function will always return a
0 status if it gets that far (and that is its final command).
Please do not treat this as an endorsement of "echo", using
printf would be better, nor for not quoting var expansions.
It is intended as a reinforcement of the:
        if you mean 'if' write 'if' not '&&'

reply via email to

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