Use a subshell to avoid having to `cd` back
Wrap a temporary `cd` in `( ... )` so the parent shell keeps its directory.
Problem
Long scripts that `cd somewhere` and forget to `cd -` end up running later commands in unexpected directories. Subshells give you a scoped working directory at no readability cost.
Bad
cd /tmp/build
make
cd .. # easy to forget; also fails silently
do_more_stuffGood
(
cd /tmp/build || exit
make
)
do_more_stuff # still in the original directoryExplanation
Anything inside `( ... )` runs in a child process. The child's `cd` cannot affect the parent's working directory, so the parent automatically returns to where it was.
Related
SC2164
When It Matters
cd into a directory, do work, cd .. back is fragile: if the work fails and the script uses set -e, or if an early return or exit fires, the cd back never runs and everything afterwards executes in the wrong directory. With relative paths and a destructive command, that is how scripts delete the wrong tree. cd .. is also wrong whenever the target was reached through a symlink or the code path could have descended more than one level, and it silently breaks if someone later changes the directory being entered.
Second Example
Note
Many tools accept a directory argument — make -C, git -C, tar -C — which is better still because nothing about the shell state changes.
Exceptions
A single unconditional cd at the top of a script that is meant to run entirely inside one directory is fine and idiomatic: cd "$(dirname "$0")" || exit 1. The warning is about the cd X; work; cd .. round trip, not about changing directory in general.
Faq
Q
Does a subshell slow the script down?
A
It forks once, which is negligible compared to almost any command you would run inside it, and far cheaper than debugging a script that ended up in the wrong directory.
Q
Do variables set inside the subshell survive?
A
No. Assignments inside ( ) are discarded when it exits. If you need a value out, echo it and capture the output, or restructure using pushd/popd.
Q
What about pushd and popd?
A
They work in Bash and keep a directory stack, but they are not POSIX and popd is skipped just as easily as cd .. when an error aborts the block.