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 CWDGood
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.