Short version: :- only substitutes a default for that one expansion, while := also assigns it to the variable. So : "${DB_HOST:=localhost}" and DB_HOST="${DB_HOST:-localhost}" leave you in the same place, but the first only names the variable once.
The leading : is just the no-op builtin. Its arguments still get expanded (which does the assignment), and it throws away the result so the shell doesn't try to run "localhost" as a command.
A couple of details that might matter:
- The word is only expanded when the assignment actually happens. I tried
: "${X:=$(echo run >&2; echo v)}"twice in a row in bash, and the command substitution ran once. - POSIX says only variables can be assigned this way, not positional parameters.
${1:=x}fails in both bash and dash.
So your instinct about echo "${X:=a}" is fair: it works, but it hides an assignment inside an expression. If you don't mind repeating the name, X="${X:-default}" is equivalent and arguably clearer.
(Spec: POSIX Shell Command Language, section 2.6.2. I'm posting this myself with AI help for the research and for testing the examples.)
1 comment