HOWTO · Bash
How to Assign Default Value in Bash
Learn how Bash parameter expansion supplies or assigns fallback values, how unset and empty variables differ, and when an if statement is a better fit.
On this page
Use Bash parameter expansion to choose a fallback while expanding a value, or to assign that fallback to a variable. For a script argument, ${1:-default_value} uses default_value when the first argument has no value to use. The distinction between choosing and assigning matters: :- does not change the parameter, while := does.
Using Bash Parameter Expansion for Defaults
Run this example:
#!/usr/bin/env bash
value=${1:-"default_value"}
printf 'value=%s\n' "$value"
value=default_value
With no first argument, the expansion selects default_value, and the command prints the resulting value. The quoted result is assigned to value, so later commands can use it without repeating the fallback expression. Quoting "$value" preserves it as one argument even if it contains spaces. Replace $1 with a variable name such as config_file to apply the same pattern to a shell variable.
Distinguishing Unset and Empty Variables
In Bash, an unset parameter has no value assigned to it; an empty (or null) parameter is set to a zero-character value. The operator without a colon and the operator with a colon treat those states differently. ${parameter-word} substitutes word only when parameter is unset. ${parameter:-word} substitutes word when it is either unset or null. In both forms, the fallback is only expanded; the parameter itself is unchanged.
For example, ${name-guest} preserves name when it is set to an empty string, while ${name:-guest} substitutes guest in that case. If only an unset variable should trigger a fallback, use the form without a colon. If both unset and empty should trigger it, use the colon form. These operators work with positional parameters too, so ${1:-guest} is a convenient way to select a default argument.
The following comparison uses separate variables for each operator so an assignment in one case cannot change the next result. A displayed <unset> means the parameter still has no value; an empty field means it is set to an empty string. In the unset and empty groups, = assigns only for unset, while := assigns for either unset or empty. Neither - nor :- assigns to its parameter. When the variable already contains ready, all four forms preserve it.
Run this Bash example:
#!/usr/bin/env bash
unset u_dash u_colon_dash u_equal u_colon_equal
u_dash_result=${u_dash-fallback}
u_colon_dash_result=${u_colon_dash:-fallback}
u_equal_result=${u_equal=fallback}
u_colon_equal_result=${u_colon_equal:=fallback}
printf 'unset results: -=%s, :-=%s, ==%s, :=%s\n' "$u_dash_result" "$u_colon_dash_result" "$u_equal_result" "$u_colon_equal_result"
printf 'unset variables: -=%s, :-=%s, ==%s, :=%s\n' "${u_dash-<unset>}" "${u_colon_dash-<unset>}" "${u_equal-<unset>}" "${u_colon_equal-<unset>}"
e_dash=''
e_colon_dash=''
e_equal=''
e_colon_equal=''
e_dash_result=${e_dash-fallback}
e_colon_dash_result=${e_colon_dash:-fallback}
e_equal_result=${e_equal=fallback}
e_colon_equal_result=${e_colon_equal:=fallback}
printf 'empty results: -=%s, :-=%s, ==%s, :=%s\n' "$e_dash_result" "$e_colon_dash_result" "$e_equal_result" "$e_colon_equal_result"
printf 'empty variables: -=%s, :-=%s, ==%s, :=%s\n' "${e_dash-<unset>}" "${e_colon_dash-<unset>}" "${e_equal-<unset>}" "${e_colon_equal-<unset>}"
s_dash=ready
s_colon_dash=ready
s_equal=ready
s_colon_equal=ready
s_dash_result=${s_dash-fallback}
s_colon_dash_result=${s_colon_dash:-fallback}
s_equal_result=${s_equal=fallback}
s_colon_equal_result=${s_colon_equal:=fallback}
printf 'set results: -=%s, :-=%s, ==%s, :=%s\n' "$s_dash_result" "$s_colon_dash_result" "$s_equal_result" "$s_colon_equal_result"
printf 'set variables: -=%s, :-=%s, ==%s, :=%s\n' "$s_dash" "$s_colon_dash" "$s_equal" "$s_colon_equal"
unset results: -=fallback, :-=fallback, ==fallback, :=fallback
unset variables: -=<unset>, :-=<unset>, ==fallback, :=fallback
empty results: -=, :-=fallback, ==, :=fallback
empty variables: -=, :-=, ==, :=fallback
set results: -=ready, :-=ready, ==ready, :=ready
set variables: -=ready, :-=ready, ==ready, :=ready
Assigning a Default with :=
The assignment operators follow the same colon distinction. ${parameter=word} assigns word to parameter only when it is unset. ${parameter:=word} assigns it when it is unset or null. The expanded result is the assigned value, and subsequent references to that variable see the assignment. Use := when the script should initialize a variable once and then rely on its value; use :- when you need a fallback for one expansion without changing the variable. The comparison above shows both conditions for each operator and the parameter values after expansion.
For example, : "${config_dir:=/etc/my-app}" assigns /etc/my-app when config_dir is unset or empty. The leading : is Bash’s null command: it expands its arguments and discards them. The assignment happens as part of expanding the argument, not because : interprets an assignment. Assignment with = or := requires an assignable variable name; positional parameters and special parameters cannot be assigned with these operators. To provide a default for $1, copy the expansion into an ordinary variable, as in the first example.
Choosing Between Parameter Expansion and if
Parameter expansion is compact when one unset-or-null rule is enough. Choose if when the fallback depends on several conditions, needs validation, or requires different actions. For example, to distinguish an unset mode from a set but empty mode, test set status with ${mode+x} and then handle each state in separate branches. An if statement also makes it straightforward to print a diagnostic or return an error before assigning a value.
If unset and empty should both select the same fallback, a simple if can use [[ -z ${mode-} ]]; if only unset should do so, test whether [[ -z ${mode+x} ]]. The -z test checks whether its string operand has length zero, so using ${mode-} gives it a safe string even when mode is unset. Prefer [[ ... ]] in Bash scripts, and quote values when passing them to commands.
Common Pitfalls and Practical Examples
Do not confuse expansion with assignment: value=${input:-guest} sets value, but leaves input untouched; input=${input:=guest} initializes input itself. Also, the colon in :- and := is part of parameter-expansion syntax. It is not the separate : command, and it does not mean that arguments are ignored. The command : may be useful to trigger an assignment expansion as shown above, but the expansion is what applies the default.
Choose the operator based on the input policy. Use - or = when an intentionally empty value should be preserved, and :- or := when empty should count as missing. When a variable may contain spaces, quote its later uses, for example printf '%s\n' "$config_dir". For a one-time positional argument default, assign ${1:-guest} to a named variable. For validation, multiple fallback rules, or user-facing error messages, use an if statement so each decision and action is explicit.