'Why does bash parse same condition in different ways? [closed]
Today I run into strange bash behaviour, i made this simple example:
#!/bin/bash
if true or ! true; then
echo a;
else
echo b;
fi
if true -o ! true; then
echo a;
else
echo b;
fi
if true || ! true; then
echo a;
else
echo b;
fi
if true or
! true; then
echo a;
else
echo b;
fi
if true -o
! true; then
echo a;
else
echo b;
fi
if true ||
! true; then
echo a;
else
echo b;
fi
The output is something unexpected for me:
a
a
a
b
b
a
I was prompted that cases 4 and 5 are treated like that:
pi@raspberrypi:~ $ if true or; ! true; then echo a; else echo b; fi
b
pi@raspberrypi:~ $ if true -o; ! true; then echo a; else echo b; fi
b
This is working code, but it looks like a syntax error for me, and in the 6th case this is it:
pi@raspberrypi:~ $ if true ||; ! true; then echo a; else echo b; fi
bash: syntax error near unexpected token `;'
The question is, is this behavior a bug or is it done intentionally? And if this is done on purpose, then what is the meaning of such differences?
Solution 1:[1]
Let's say the overall syntax of if is:
if
list-of-commands
then
another-list-of-commands
fi
If list-of-commands exits with zero exit status, then another-list-of-commands is executed. Zero exit status is also called a "success", whereas non-zero is, well, called a "failure".
The overall rule of thumb, is that the exit status of any list of commands is the exit status of the last command executed.
The "list-of-commands" can contain multiple list-of-commands "inside" and multiple commands inside. You can put whole scripts in there.
if true or ! true; then
true is a command that exits with zero exit status. The executable true is executed with 3 arguments - string or, string ! and string true. The command true ignores arguments and exits with zero exit status.
Note that or is just or the string or it has no special meaning.
if true -o ! true; then
Same as above, just second argument is the string -o. Once again -o are characters -o.
if true || ! true; then
|| is special. || executes the command on the right side when the command on the left side exits with non-zero exit status. The exit status of || is the exit status of the command last executed.
true exits with zero exit status. || does not execute the right side. The last command is true and exited with zero exit status. The exit status of the list true || ! true is zero.
if true or ! true; then
Formatting:
if
true or
! true
then
There are two commands here.
First true command is executed with one argument or. Its exit status is ignored.
Then true command is executed, it exits with zero exit status. ! "inverts" the exit status, so the exit status of ! true is one.
The exit status of the list of commands true or ; ! true is the exit status of the last command executed. ! true was last, it exited with non-zero. Execution is goes to the else branch.
if true -o ! true; then
As above.
if true || ! true; then
Empty lines or with only whitespaces and only a comment after || are ignored. This is exactly the same as the if true || ! true; then case.
if
true ||
# yay a comment here
# ^^ and empty lines too!
! true
then
if true ||; ! true; then
The syntax is command || command. ; ends a list of commands. There is no command after ||. Thus, it's a syntax error.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
