Thursday, December 2, 2010

Bash Braindeadness: Logical Connectives

UPDATE: As was pointed out on Ubuntuforums, "true -a false" on its own is running command "true" with parameters "-a" and "false", and "true" deliberately silently ignores its arguments. So again, "-a" & "-o" have logical connective semantics only as arguments to test/[. The below is stylistic feature ;-).

So I've been debugging a shellscript which didn't do what it should have been (not mine). Everyone likes using kewl idioms, so there was:

check val1 -a check val2 && do_something

Well, just gotta choose right language. Because in bash:

$ false -a false; echo $?
$ false -a true; echo $?
$ true -a false; echo $?
$ true -a true; echo $?

Wanna more? Easily:

$ false -o false; echo $?
$ false -o true; echo $?
$ true -o false; echo $?
$ true -o true; echo $?

So, from looks of these examples, in bash, both logical AND and OR have the same truth table, and semantics of "return first argument". Now, wazzup?

Googling surprisingly doesn't give good hits - obviously, because you have troubles searching for "-a", "-o", "and" or "or". Googling for "logical and in bash" gives one good hit on 1st page - There, some guy wonders why both [ 0 -a 0 ] and [ 0 -a 1 ] are true, but not really being answered.

So, by reading man bash a really careful reader may notice that -a and -o (in a sense of binary logical connectives) are defined within description of test aka [ command. The description also says "Expressions are composed of the primaries described above under CONDITIONAL EXPRESSIONS." And CONDITIONAL EXPRESSIONS list only checks like -a and comparisons, and no thing like shell commands, integer or string literals, etc. So, careful deductive reader might pose hypothesis:

Logical -a, -o are defined only within scope of test aka [ command. And there, they must apply only to legitime boolean expressions - checks and comparisons. Usage of -a, -o in any other context silently produces undefined result.

Of course, any decent language would give error if some operator is used in wrong context. But Unix shell in general, and Bash in particular, have always been special. So, be it historically preserved bug, or GNU Bash own invention, the end result is the same - you don't need the Brainfuck language or other alike novelties to have some fun - with bash, you can get unexpected results right at your fingertips, at any Linux workstaion around the world.

No comments: