On Thu, Aug 11, 2011 at 11:56:10PM -0700, Linda Walsh wrote: > **Exception** > declare -i a > a=0 > -- > As a is declared to be an integer, it has the results evaluated > at assignment time. a=0 is an integer expression that doesn't set > $?=1 > Neither should: > ((a=0))
a=0 is an assignment. Assignments always return 0. ((a=0)) is an arithmetic command. It has the *side effect* of putting the value 0 into the variable a, but its primary goal is to evaluate the mathematical expression inside of the parens, in the same way that C does, and return 0 ("true") or 1 ("false"). In C, if you write the expression a=0, for example: if (a=0) { the expression a=0 will be evaluated for truth-or-falseness. This is done by performing the implicit assignment, and then using the value assigned as an integer which is compared to 0; if that value is 0 then the expression is considered "false", and if it's nonzero, the expression is considered "true". Granted, the C code shown above is most typically a mistake (a==0 is what is usually wanted), and in fact many compilers will issue a warning if they see it. Back to bash, imadev:~$ a=0; ((a==1234)); echo $? 1 ((...)) performs a comparison between the two integer values, testing them for equality. They are unequal, so it returns false (1). This is how ((...)) is primarily *intended* to be used. imadev:~$ a=3; while ((--a)); do echo x; done x x Another intended use: pre-decrement the variable, and then compare the value of the variable to 0. If the value is 0, then return false, thus terminating the loop. imadev:~$ ((a=17)); echo $? 0 An unintended use. Assign 17 to the variable, but because we are performing an arithmetic expression evaluation, we also evaluate this value (compare it to 0). It's nonzero, so we return true. imadev:~$ ((a=0)); echo $? 1 And here, the same thing, but we return false, because the value was 0. This is the thing about which you are complaining. This is also one of the things I mention on http://mywiki.wooledge.org/BashFAQ/105 in which I describe how horrible and useless set -e is. (Uh oh, bash changed *again* since I wrote http://mywiki.wooledge.org/BashFAQ/105/Answers and now I have to update both pages... I'll get to that in a moment. But this just reinforces my point!) imadev:~$ : $((a=0)); echo $? 0 Here, an assignment inside an arithmetic context, but ignoring the evaluation of the expression. The : command forces $? to be 0. The side effect of the arithmetic expression (the assignment of 0 to a) still occurs. This is also POSIX-compatible! This is how you do ((...)) in POSIX shells. It also negates your problems with set -e, should you continue in your attempts to use set -e, for some reason. > set -e is a valuable development aid I hold a different opinion of it. > to ensure that all your *ERRORS* > are caught by the script, and not allowed to execute 'unhandled'. I do not believe the intent of set -e was ever to catch *programmer* errors. It was intended to catch failing commands that would cascade into additional failures if unhandled -- for example, cd /foo rm -rf bar If the cd command fails, we most certainly *don't* want to execute the rm command, because we'd be removing the wrong thing. set -e allows a lazy programmer to skip adding a check for cd's failure. A wiser programmer would skip the set -e (knowing how fallible and cantankerous it is), and check cd's success directly: cd /foo || exit rm -rf bar