Use "${var:?}" to ensure this never expands to /*

When `$dir` is empty, `rm -rf "$dir"/*` becomes `rm -rf /*`. Guard with `${dir:?}`.

Problem

An empty variable turns a path like `"$root/cache"` into `"/cache"` — and `"$root"/*` into `/*`. With `rm -rf`, that's a fleet-deleting bug. ShellCheck flags any rm/chmod/chown command whose path could collapse to root.

Bad

dir=$1
rm -rf "$dir"/*

Good

dir=$1
rm -rf "${dir:?dir is unset or empty}"/*

Explanation

`${var:?message}` aborts the script with the given message when `var` is unset or empty. It is one line of defense that converts a catastrophic bug into a clear error.

When It Matters

rm -rf "$dir/" is one unset variable away from rm -rf "/". Scripts run in CI, in containers as root, and in cron jobs where an environment variable that exists locally is simply absent — and the resulting command deletes the root filesystem without a single warning. This is not theoretical: it is the single most-cited class of catastrophic shell bug, and it has taken out production hosts and shipped in installers from well-known vendors.

Second Example

Note

The ${var:?} form fails the command rather than expanding to nothing, which converts a silent catastrophe into an ordinary error message.

Exceptions

There is no good reason to skip the guard on a recursive delete. If the variable is a literal constant assigned two lines above, the risk is lower, but the guard costs three characters and survives the refactor that later makes the value dynamic.

Faq

Q

What exactly does ${var:?} do?

A

If the variable is unset or empty, the shell prints an error and exits (or, in an interactive shell, returns to the prompt) rather than substituting an empty string.

Q

Does set -u make the guard unnecessary?

A

It catches unset variables but not empty ones. ${var:?} catches both, so the two are complementary.

Q

Why add -- before the path?

A

It stops a path beginning with a dash being parsed as an option. It is cheap insurance on every rm, cp, and mv that takes a variable path.