Skip to content
shellhacks.dev
Command Line

Delete a Directory Safely in a Bash Script with rm -rf

Protect rm -rf "$dir/" from an empty variable with set -u or the ${dir:?message} expansion, which stops the script before the command starts. Works in Bash and POSIX sh.

1 min read
Summarize in AI

A cleanup line such as rm -rf "$dir/" turns into rm -rf / when the variable is empty, and you want the script to stop first.

Shell
mkdir -p build/obj && touch build/obj/a.o
rmrf() { echo "would run: rm -rf $1/"; }
dir=
rmrf "$dir"
set -u
unset dir
( rmrf "$dir" ) 2>&1
( echo "would run: rm -rf ${dir:?refusing to continue}/" ) 2>&1
dir=build
echo "would run: rm -rf ${dir:?refusing to continue}/"
Text
would run: rm -rf /
bash: line 7: dir: unbound variable
bash: line 8: dir: refusing to continue
would run: rm -rf build/

The first call in the run shows the danger: an empty dir leaves only /. set -u makes any unset variable an error, and ${dir:?message} is stricter, because it aborts when the variable is unset or empty and prints the message. Both stopped the subshell before the command would have started, and the run only echoes the command, so nothing was deleted. The :? form is described in Shell Parameter Expansion.

set -u alone does not catch a variable that is set to an empty string; only :? does. GNU rm refuses rm -rf / unless --no-preserve-root is given, but /* and a path built from several variables have no such guard, so check the value and not only that it exists.

Share

More snippets

Get new posts by email

One email when a new post is published. No spam.

Unsubscribe in one click. No spam, ever.