In an answer to another very good question I made the following assertion:
According to my reading of the POSIX specs, the use of one or the other makes no difference from a parsing standpoint.
POSIX specifies that &&||
lists are compound commands which means that the entire list must be read in and parsed before execution of the constituent simple commands. POSIX also specifies a command shall not be expanded if it follows an ||OR
and another command with a 0-exit status. When you consider that a command following an &&||
reserved word can easily be another grouped { command || ( command ; list) ; }
makes each branch of the &&||
or list its own compound command.
But POSIX also specifies that each branch of the if...;then...;else...fi
construct be its own compound command in this way:
if compound-list
then
compound-list
[elif compound-list
then
compound-list] ...
[else
compound-list]
fi
The
if
compound-list shall be executed; if itsexit
status is zero, thethen
compound-list shall be executed and the command shall complete…
It is this specification that the string following a then...
or else...
reserved words are compound commands in their own right and not merely simple commands that means the shell's parser must denote them with a command and a delimiter in order to operate correctly.
So basically, then ' '
doesn't work for the same reason:
function()
sh: line 2: syntax error: unexpected end of file
…doesn't – it doesn't make any sense.
I know that…
[ -e doesntexist ] && $((i=1)) ; echo $i
…will short-circuit any side-effects and result in only a \n
ewline as a result of the spec I noted in my answer. The result of…
if [ -e doesntexist ]
then $((i=1))
fi
echo $i
…is identical.
But I honestly use if...fi
so seldom that I'm unsure if I've misread something and so when I received a comment indicating my interpretation was incorrect and that if I had further questions on the matter I need only ask I deleted the answer in lieu of this question: how have I got it wrong – how do they differ?
Best Answer
Only simple cases can be expressed with
&&
and||
. Theif
construct is more general.if CONDITION; then FOO; fi
is equivalent toCONDITION && FOO
(assuming proper usage of braces to delimit a block if necessary), but as soon as there's anelse
(orelif
), this is no longer possible in general.is not equivalent to
If
CONDITION
is true, both constructs executeFOO
. IfFOO
is false, then theif
construct skipsBAR
, whereas the&& … ||
construct executesBAR
.And no, you can't work around this with
CONDITION && { FOO; true; } || BAR
. This makes the compound command return true ifCONDITION
is true andFOO
is false, whereasif CONDITION; then FOO; else BAR; fi
returns false in that case.That's for the semantic difference. In addition, there's readability: nested uses of
&&
and||
very quickly become hard to decipher. I don't recommend using both in the same command, in fact — especially given that the two operators have equal precedence in the shell, whereas they have different precedences in C and most other C-inspired languages (including Perl and Ruby).