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
ifcompound-list shall be executed; if itsexitstatus is zero, thethencompound-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 \newline 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?
[ -e doesntexist ] && $((i=1))actually, but I'd already edited that, hadn't I? I'm specifically talking about the parse order - sometimes commands are evaluated more times than they are executed, which is why: $((i=1)) ; echo $iwill get you1.&&or||. The difference is that if thethenblock is executed then theelseblock is never executed. But with&& / ||it always depends on the exit code of the currently executed block.: $((i=1)) ; echo $iis a strange example as there is no control flow at all.:is executed (it's a noop, not a comment!), and$((i=1))is not a command at all but an expansion.[ -e doesntexist ] && $((i=1)) ; echo $idoesn't output1– except for ifiwas1before already...if true; then { echo true; test -e doesntexist; }; else echo false; fivs.true && { echo true; test -e doesntexist; } || echo falsevs.true && { echo true; test -e /; } || echo false