A && B || C is not if-then-else

The `cmd1 && cmd2 || cmd3` idiom runs cmd3 whenever cmd2 fails — not what most people expect. Use an explicit if.

Problem

`A && B || C` looks like a one-line if/else, but it isn't: if A succeeds and B then fails, C runs anyway. This bites when B is a non-trivial command — a failed log line silently triggers the error branch.

Bad

[ -f file ] && rm file || echo "missing"
# If the rm fails (read-only filesystem), "missing" prints — wrong!

Good

if [ -f file ]; then
  rm file
else
  echo "missing"
fi

Explanation

The short-circuit form is only safe when B is guaranteed to succeed (a constant assignment, for example). When B can fail, use an explicit `if` so the else branch is tied to the condition, not to B's exit status.

When It Matters

a && b || c looks like if-then-else but is not: if a succeeds and b fails, c runs too. Any b that can fail — a grep with no match, an echo to a full disk, an arithmetic expression evaluating to zero — turns the "else" branch into an "also" branch. The classic silent version is check && count=$((count+1)) || log_error, where the arithmetic returns 1 when the result is zero and the error path fires on a perfectly successful run.

Second Example

Note

The x || { ...; } form has no third branch, so it cannot misfire — it is the version of this idiom that is always safe.

Exceptions

When b cannot fail — a plain assignment to a variable, or : as a no-op — the idiom is safe and idiomatic. Reviewers cannot check that at a glance, so an if statement is still usually the kinder choice in shared code.

Faq

Q

Why does my counter increment trigger the error branch?

A

(( count++ )) returns exit status 1 when the value before incrementing was zero. Use (( ++count )) or append || true.

Q

Is the idiom ever preferable to if?

A

For a one-line guard clause that exits, yes — it reads well and there is no else to get wrong.

Q

Does set -e interact with this?

A

Commands on the left of && or || are exempt from set -e, so failures there do not abort the script. That is another reason the construct surprises people.