DEV Community

Schiff Heimlich
Schiff Heimlich

Posted on

Bash Parameter Expansion: Two Quirks That Slip Through Code Reviews

Bash Parameter Expansion: Two Quirks That Slip Through Code Reviews

Here's a pair of bash parameter expansion behaviors that I've seen slip through code reviews and cause intermittent failures in production scripts. Small stuff, but worth knowing.

${var:-default} vs ${var-default}

This trips people up constantly. The colon matters:

var=""  # var is set, but empty

echo "${var:-default}"   # prints: default
echo "${var-default}"     # prints: (empty)
Enter fullscreen mode Exit fullscreen mode

With the colon, bash checks if the variable is unset OR empty. Without the colon, it only checks if the variable is unset. So an empty string gets treated as "use the default" with :-, but as "use the empty value" without.

In practice, this matters most when you're handling environment variables or config values that might legitimately be empty:

# Safe: use default only when truly absent
HOME_DIR="${HOME:-/root}"

# Unsafe: empty HOME would still use /root
HOME_DIR="${HOME-/root}"
Enter fullscreen mode Exit fullscreen mode

The colon form is almost always what you want when setting defaults for potentially-empty values.

[[ -v var ]] vs [[ -n $var ]]

Another subtle one. -v checks if a variable is declared (and non-empty in bash 4.2+). -n checks if the value is non-empty.

var=""  # declared but empty

[[ -v var ]]    # true (var exists)
[[ -n $var ]]   # false ($var expands to empty string)
[[ -n "$var" ]] # false (same, quoted or not)
Enter fullscreen mode Exit fullscreen mode

The -n "$var" version is actually checking if the quoted string is non-empty, which is always false for an empty variable. But -v correctly identifies that the variable exists, regardless of its value.

This shows up when checking if optional flags were passed:

VERBOSE=""  # passed but empty

[[ -v VERBOSE ]] && echo "verbose mode"     # correctly matches
[[ -n $VERBOSE ]] && echo "verbose mode"     # misses it
Enter fullscreen mode Exit fullscreen mode

For declared/empty check: use -v. For "has non-empty value" check: use -z or -n "$var".

Practical Takeaway

When writing scripts that handle config or environment variables, prefer ${var:-default} and [[ -v var ]]. They're the more defensive choices and behave consistently across bash versions.

Top comments (0)