Skip to content
AgileLogics
5 min read

Exit Codes, &&, and ||

Prerequisites: How the shell runs commands

Every command returns an exit status: 0 for success, 1–255 for failure. Bash uses these to decide what to run next.

&& and ||

  • a && b — run b only if a succeeded.
  • a || b — run b only if a failed.
mkdir project && echo "Created project"
mkdir project 2>/dev/null || echo "Couldn't create project (it already exists)"
cd project && touch README.md && ls
Created project
Couldn't create project (it already exists)
README.md

Chains like cd project && make && ./run-tests stop at the first failure — you'd never want to run tests if the build failed.

; runs regardless

a ; b runs b after a, whether a succeeded or not.

true, false, and $?

true
echo "true returns $?"
false
echo "false returns $?"
grep -q "needle" <<< "haystack"
echo "grep returns $? when it finds nothing"
true returns 0
false returns 1
grep returns 1 when it finds nothing

grep -q ("quiet") prints nothing and only reports, through its exit status, whether it found a match — perfect for conditions.

Setting your own exit status

exit N ends a script with status N. Scripts should exit 0 on success and non-zero on failure, so that other scripts, cron, and CI systems can tell whether they worked.

Common mistakes

  • a && b || c looks like if/else but isn't: if b fails, c runs too. For real if/else logic, use if (next lesson).
  • Ignoring failures: a script that keeps going after a command fails can do real damage (for example, cd fails and the next rm runs in the wrong folder). Level 3's strict mode helps.