Date: Wed, 30 May 2018 17:02:58 -0700 From: L A Walsh <b...@tlinx.org> Message-ID: <5b0f3bb2.1000...@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