Your confusion stems from the fact that many popular languages (especially C-based ones) stop evaluating
&& sequences when 0 is encountered, because 0 is considered
false and everything else is
true. In Bash, however, that's not the case. By convention, in POSIX systems (and all other Unix-like systems), return code 0 is considered
SUCCESS (there was no error, so nothing is returned) and a non-zero return code is considered
FAILURE. Every command in Bash, be it an external program such as a C program or a shell builtin, must return a value:
A simple command is a sequence of optional variable assignments
followed by blank-separated words and redirections, and
terminated by a control operator. The first word specifies the
command to be executed, and is passed as argument zero. The
remaining words are passed as arguments to the invoked command.
The return value of a simple command is its exit status, or
128+n if the command is terminated by signal n.
builtin commands return a status of 0 (true) if successful, and
non-zero (false) if an error occurs while they execute. All
builtins return an exit status of 2 to indicate incorrect usage.
A return value is not a Boolean, though. It's a number between 0 and 255:
The exit status of an executed command is the value returned by
the waitpid system call or equivalent function. Exit statuses fall
between 0 and 255, though, as explained below, the shell may use
values above 125 specially. Exit statuses from shell builtins and
compound commands are also limited to this range. Under certain
circumstances, the shell will use special values to indicate
specific failure modes.
For the shell's purposes, a command which exits with a zero exit
status has succeeded. An exit status of zero indicates success.
A non-zero exit status indicates failure. When a command
terminates on a fatal signal N, bash uses the value of 128+N as
the exit status.
When a command reports its return code back to the shell, it's generally enough to check whether the exit code is 0 or not.
Now, the next command in a list glued together with
&& will be executed only if the previous command returned 0—i.e.
AND and OR lists are sequences of one or more pipelines separated
|| control operators, respectively. AND and OR lists are
executed with left associativity. An AND list has the form
command1 && command2
command2 is executed if, and only if, command1 returns an exit status