true || false means "false" is executed, yes?
No. true has a 0 exit code. As it IS executed,
$?
is
0
, based on that, the shell does NOT execute the command following
||
.
false && echo yes means echo is not executed, no?
Yes, obviously. But in the whole line,
false
is never executed.
I assume you are still thinking "too complicated". The shell does not evaluate any expressions here. What happens is like this:
Bash:
true \ # just a new command, always executed, $? is 0 now
|| false \ # as $? is 0, the command following the || is ignored
&& echo yes # $? is still 0, so the command following the && is executed
See also these experimental snippets:
Bash:
$ true || false
$ echo $?
0
$ if true || false; then echo yes; fi
yes
$ if true || false && false; then echo yes; fi
$ if false && false || true; then echo yes; fi
yes
$
Whether this behavior of the shell is good, logical, whatever, you could probably argue a lot about. I personally think it does make perfect sense, because as mentioned above, the shell does not evaluate any expression here but really executes a script step by step. But well ...
Anyways, this is the standard POSIX behavior of a bourne shell.
And so it is ONE of many issues with C shells. They try to "be clever" (in, let's do it more like C, so C programmers understand it), but exposing different behavior in such things just causes confusion and destroys portability. Disclaimer: Yes, I really really dislike shells that don't conform to POSIX by design ?
edit:
My takeaway from this whole thing is "Parens and grouping are important. Say what you mean don't assume something else is going to do what you want".
Also careful with that. If you'd write
true || (false && echo yes)
, this would mean the
false && echo yes
part would be executed by a
subshell, IOW, a child process. This might not be what you want. Sure, it WOULD have the effect of not outputting yes, because in the subshell, the
false
is executed unconditionally, setting
$?
to something non-zero, therefore the
&&
would make the shell ignore the following command. (
edit2: well, if the subshell would be executed at all that is ... which it won't here, because it's guarded by a ||
... but at least same result in the end!)
But that's not the actual
purpose of parentheses in bourne shell, their purpose is to execute something in a subshell.