Use `cd ... || exit` to handle a failed `cd`

If `cd` fails the script keeps running in the wrong directory. Always pair it with `|| exit` or `|| return`.

Problem

When `cd /some/dir` fails (typo, missing directory, permission denied), Bash prints an error and continues executing in the *current* directory. Subsequent commands — including `rm -rf *` cleanup — then operate on the wrong target. This pattern has nuked countless home directories.

Bad

cd "$build_dir"
rm -rf ./*           # If cd failed, this deletes everything in the CWD

Good

cd "$build_dir" || exit 1
rm -rf -- ./*

# Or with set -e:
set -euo pipefail
cd "$build_dir"
rm -rf -- ./*

Explanation

`|| exit` makes the failure fatal at the point it happens. Even better, run the whole script under `set -euo pipefail` so every command failure aborts the script, not just `cd`. For functions, use `|| return` instead of `|| exit` so callers can recover.

Related

SC2103

SC2181

When It Matters

If cd fails — the directory does not exist, permission is denied, a mount disappeared — the script carries on in the previous directory and every subsequent relative path targets the wrong place. When the next command is rm -rf ./build or a git clean, the consequences are permanent. This is the highest-impact one-character-per-line fix in shell scripting: every cd should either be checked or run under a shell that aborts on failure.

Second Example

Note

set -e alone does abort on a failed cd, but the explicit || exit documents the intent and keeps working if someone later removes set -e.

Exceptions

A cd inside a condition — if cd "$dir"; then — is already checked, and so is one on the left of &&. ShellCheck recognises both, so a remaining warning means the failure really is unhandled.

Faq

Q

Does set -e cover this?

A

Yes for a bare cd, but not when the cd is part of a compound command or a pipeline. The explicit form is unconditional.

Q

Should I use cd -- "$dir"?

A

It is worth it when the path comes from a variable, since a directory named -P would otherwise be read as an option.

Q

How do I return to where I started?

A

Use a subshell so no return is needed, or save it first: orig=$PWD, then cd "$orig" in a trap.