bug-bash
[Top][All Lists]
Advanced

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

Re: Conditions with logical operators and nested groups execute "if" and


From: Robert Elz
Subject: Re: Conditions with logical operators and nested groups execute "if" and "else"
Date: Thu, 31 May 2018 13:54:14 +0700

    Date:        Wed, 30 May 2018 17:02:58 -0700
    From:        L A Walsh <bash@tlinx.org>
    Message-ID:  <5B0F3BB2.1000006@tlinx.org>

  | I.e. precedence rules seem to work as expected.

I am not sure what predence rule you see working as
expected, but in sh (bash, or any other Bourne syntax
or POSIX shell) there is no precedence for && and ||
they (in the absense of grouping) are simply executed
left to right as written.

With grouping the commands in the group are executed
as a unit (according to whatever rules apply to whatever
commands are there) and appear as a single command
to the and-or list.

The examples you are using to test this are way too
simple and give results that are easy to misinterpret,

But the rule is simple - in an and-or list, the first command
is executed, and produces an exit status, which for this
then gets interpreted as true (0) or false (anything else).

When that command is done, and the following operator
is && or || then that status is used to determine whether or
not the immediately following command is executed or not.

If the operator is && then the next command is executed if
the current exit status is "true", otherwise the next command
is simply skipped, and we move to the next operator.   If the
operator is || then the next command is executed if the
current exit status is false, otherwise the next command is
skipped. 

When a command is skipped the exit status is not changed,
so if the following operator (&& or ||) is the same as the last
one, and the preceding command was skipped, then so will
the next one be.   Always.   Whenever a command is exexuted
it sets the exit status that is used to decide what to do at the
following operator.

When there are no more || or && operators left, the final exit
status of the list is the status that resulted from the last command
that was executed.

How this is unlike what would be seen in a mathematical (or just
about any other programming language) usage, is seen in
something like

false && anything || true || anything && false && anything

where what the "anything" are makes no difference at all in sh,
but in C (etc) the one immediately after the second || would be
evaluated before seeing the "false" that follows (or more accurately,
that false would never be executed either as the result would have
already been determined to be true.) 

In sh that does not happen, because the status at that || is "true" so
the following command is not executed, but we continue to the
following && and the status has not changed, so the command after
that  "false") is executed, and is the last command executed (the &&
and false exit status means the final "anything" is skipped), so the
exit status of the list is false (1) not true as it would be in C.

This is easy to test, you can run that command exacty as typed,
that there is nothing installed called "anything" makes no
difference at all.   Do check the exit status at the end.

and-or lists are generally only equivalent to if ... then in the case
where there is a single command being tested, and when the exit
status of the whole thing is irrelevant.

that is
        command && other
is the same as
        if command; then other; fi
and
        command || other
is the same as
        if ! command; then other; fi
provided, in both cases, that we do not care what $? is
when this finishes.

Attempting to use && and || together to make an if/then/else
combination is usually a big mistake - if it works at all it
is usually only because the "then" command always returns
true (because of what it happens to be).  If iit can ever
fail, then always use if explicitly, not an and-or list.

That is, something like

        $casesensitive && grep $expr $files || grep -i $expr $files

is always wrong.  If $casesensitive is true, the grep -i is done, and if
it works (finds expr in files) then all is good, but if it fails (the expr is
not present) the exit status at the || will be false, and so the
second grep (with -i) will also be attempted just as it would have
been if $casesensitive had been false.

kre




reply via email to

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