cmd1; cmd2 executa cmd1 e, em seguida, cmd2 , não importa o quê. É exatamente equivalente a colocar cmd1 e cmd2 em linhas separadas¹. O status de retorno desse comando composto é de cmd2 .
cmd1 && cmd2 executa cmd1 . Em seguida, se o status de saída de cmd1 for zero, cmd2 será executado. O status de retorno desse comando composto é cmd1 se for diferente de zero (portanto, cmd2 não foi executado) e cmd2 (caso tenha sido executado).
if cmd1; then cmd2; fi é principalmente equivalente a cmd1 && cmd2 . A principal diferença é que a versão com if retorna 0 se cmd1 retornar um status diferente de zero.
Um comando retorna 0 para indicar sucesso, e um código de erro diferente de zero (entre 1 e 255, geralmente entre 1 e 125, como valores mais altos têm outros significados) para indicar falha. Assim, cmd1; cmd2 significa “execute estes comandos em seqüência, não importa o que”, enquanto cmd1 && cmd2 significa “execute estes comandos, mas pare imediatamente se o primeiro comando falhar”.
Você pode dizer ao shell para entrar no modo "sair no erro" executando set -e . Nesse modo, o shell sai assim que qualquer comando retorna um status diferente de zero, exceto em construções condicionais (o lado esquerdo de && ou || , a parte de condição de if e while ). Assim, sob set -e , ; (ou uma nova linha) é efetivamente equivalente a && ².
¹ Em termos de fluxo de controle, isto é. As novas linhas e os pontos-e-vírgulas são executados exatamente da mesma maneira, mas não são analisados exatamente da mesma maneira. alias ls=true; ls executa ls e não true porque o analisador executa resolução de alias em ls antes de executar a definição de alias.
Sub Isso não quer dizer que você pode substituir cegamente && por ; se você adicionou set -e . Por exemplo, ; tem precedência menor que && , então cmd1 && cmd2 || cmd3 é equivalente a set -e; { cmd1; cmd2; } || cmd3 . Além disso, set -e interage mal com subcamadas - os detalhes podem atrapalhar essa resposta muito longe.