I have been looking at a few scripts other people wrote (specifically Red Hat), and a lot of their variables are assigned using the following notation VARIABLE1="${VARIABLE1:-some_val}" or some expand other variables VARIABLE2="${VARIABLE2:-`echo $VARIABLE1`}"

What is the point of using this notation instead of just declaring the values directly (e.g., VARIABLE1=some_val)?

Are there benefits to this notation or possible errors that would be prevented?

Does the :- have specific meaning in this context?

  • 4
    Crazy how after 20 years using the shell I have never come to see this notation yet! Commented Mar 6, 2023 at 20:37

4 Answers 4


This technique allows for a variable to be assigned a value if another variable is either empty or is undefined. NOTE: This "other variable" can be the same or another variable.


    If parameter is unset or null, the expansion of word is substituted. 
    Otherwise, the value of parameter is substituted.

NOTE: This form also works, ${parameter-word}. According to the Bash documentation, for all such expansions:

Omitting the colon results in a test only for a parameter that is unset. Put another way, if the colon is included, the operator tests for both parameter’s existence and that its value is not null; if the colon is omitted, the operator tests only for existence.

If you'd like to see a full list of all forms of parameter expansion available within Bash then I highly suggest you take a look at this topic in the Bash Hacker's wiki titled: "Parameter expansion".


variable doesn't exist

$ echo "$VAR1"

$ VAR1="${VAR1:-default value}"
$ echo "$VAR1"
default value

variable exists

$ VAR1="has value"
$ echo "$VAR1"
has value

$ VAR1="${VAR1:-default value}"
$ echo "$VAR1"
has value

The same thing can be done by evaluating other variables, or running commands within the default value portion of the notation.

$ VAR2="has another value"
$ echo "$VAR2"
has another value
$ echo "$VAR1"


$ VAR1="${VAR1:-$VAR2}"
$ echo "$VAR1"
has another value

More Examples

You can also use a slightly different notation where it's just VARX=${VARX-<def. value>}.

$ echo "${VAR1-0}"
has another value
$ echo "${VAR2-0}"
has another value
$ echo "${VAR3-0}"

In the above $VAR1 & $VAR2 were already defined with the string "has another value" but $VAR3 was undefined, so the default value was used instead, 0.

Another Example

$ VARX="${VAR3-0}"
$ echo "$VARX"

Checking and assigning using := notation

Lastly I'll mention the handy operator, :=. This will do a check and assign a value if the variable under test is empty or undefined.


Notice that $VAR1 is now set. The operator := did the test and the assignment in a single operation.

$ unset VAR1
$ echo "$VAR1"

$ echo "${VAR1:=default}"
$ echo "$VAR1"

However if the value is set prior, then it's left alone.

$ VAR1="some value"
$ echo "${VAR1:=default}"
some value
$ echo "$VAR1"
some value

Handy Dandy Reference Table

Parameter set and not null Parameter set but null Parameter unset
${parameter:-word} substitute parameter substitute word substitute word
${parameter-word} substitute parameter substitute null substitute word
${parameter:=word} substitute parameter assign word assign word
${parameter=word} substitute parameter substitute null assign word
${parameter:?word} substitute parameter error, exit error, exit
${parameter?word} substitute parameter substitute null error, exit
${parameter:+word} substitute word substitute null substitute null
${parameter+word} substitute word substitute word substitute null

(Screenshot of source table)

This makes the difference between assignment and substitution explicit: Assignment sets a value for the variable whereas substitution doesn't.


  • 18
    Using echo "${FOO:=default}" is great if you actually want the echo. But if you don't, then try the : built-in ... : ${FOO:=default} Your $FOO is set to default as above (i.e., if not already set). But there's no echoing of $FOO in the process.
    – fbicknel
    Commented Aug 10, 2017 at 19:50
  • 3
    Ok, found an answer: stackoverflow.com/q/24405606/1172302. Using the ${4:-$VAR} will work. Commented Jan 19, 2018 at 9:23
  • 1
    It also allows users to provide their own value for a given variable. This can be very useful when working around issues not foreseen at the time the script was written. Commented May 1, 2019 at 11:27
  • 1
    wiki.bash-hackers.org is currently down: github.com/rawiriblundell/wiki.bash-hackers.org Commented Jun 7, 2023 at 10:49
  • 1
    @PerLundberg - ty I've updated it w/ archive.org - web.archive.org/web/20200309072646/https://….
    – slm
    Commented Jun 30, 2023 at 20:36

@slm has already included the POSIX docs - which are very helpful - but they don't really expand on how these parameters can be combined to affect one another. There is not yet any mention here of this form:

${var?if unset parent shell dies and this message is output to stderr}

This is an excerpt from another answer of mine, and I think it demonstrates very well how these work:

    sh <<-\CMD
    _input_fn() { set -- "$@" #redundant
            echo ${*?WHERES MY DATA?}
            #echo is not necessary though
            shift #sure hope we have more than $1 parameter
            : ${*?WHERES MY DATA?} #: do nothing, gracefully
    _input_fn heres some stuff
    _input_fn one #here
    # shell dies - third try doesnt run
    _input_fn you there?
    # END
heres some stuff
sh: line :5 *: WHERES MY DATA?

Another example from same:

    sh <<-\CMD
    N= #N is NULL
    _test=$N #_test is also NULL and
    v="something you would rather do without"    
    ( #this subshell dies
        echo "v is ${v+set}: and its value is ${v:+not NULL}"
        echo "So this ${_test:-"\$_test:="} will equal ${_test:="$v"}"
        ${_test:+${N:?so you test for it with a little nesting}}
        echo "sure wish we could do some other things"
    ( #this subshell does some other things 
        unset v #to ensure it is definitely unset
        echo "But here v is ${v-unset}: ${v:+you certainly wont see this}"
        echo "So this ${_test:-"\$_test:="} will equal NULL ${_test:="$v"}"
        ${_test:+${N:?is never substituted}}
        echo "so now we can do some other things" 
    #and even though we set _test and unset v in the subshell
    echo "_test is still ${_test:-"NULL"} and ${v:+"v is still $v"}"
    # END
v is set: and its value is not NULL
So this $_test:= will equal something you would rather do without
sh: line 7: N: so you test for it with a little nesting
But here v is unset:
So this $_test:= will equal NULL
so now we can do some other things
_test is still NULL and v is still something you would rather do without

The above example takes advantage of all 4 forms of POSIX parameter substitution and their various :colon null or not null tests. There is more information in the link above, and here it is again.

Another thing that people often don't consider about ${parameter:+expansion} is how very useful it can be in a here-document. Here's another excerpt from a different answer:


Here you'll set some defaults and prepare to print them when called...

    _top_of_script_pr() ( 
        IFS="$nl" ; set -f #only split at newlines and don't expand paths
        printf %s\\n ${strings}
    ) 3<<-TEMPLATES
        ${PLACE:="your mother's house"}
        ${EVENT:="the unspeakable."}
            I went to ${PLACE} and saw ${EVENT}
            If you do ${ACTION} you will ${RESULT}


This is where you define other functions to call on your print function based on their results...

    EVENT="Disney on Ice."
    _more_important_function() { #...some logic...
        [ $((1+one)) -ne 2 ] && ACTION="remedial mathematics"
    _less_important_function() { #...more logic...
        : "${ACTION:="calligraphy"}"


You've got it all setup now, so here's where you'll execute and pull your results.

    : "${PLACE:="the cemetery"}" 
    : "${RESULT:="regret it."}" 


I'll go into why in a moment, but running the above produces the following results:

_less_important_function()'s first run:

I went to your mother's house and saw Disney on Ice.

If you do calligraphy you will succeed.

then _more_important_function():

I went to the cemetery and saw Disney on Ice.

If you do remedial mathematics you will succeed.

_less_important_function() again:

I went to the cemetery and saw Disney on Ice.

If you do remedial mathematics you will regret it.


The key feature here is the concept of conditional ${parameter} expansion. You can set a variable to a value only if it is unset or null using the form:


If instead you wish to set only an unset variable, you would omit the :colon and null values would remain as is.


You might notice that in the above example $PLACE and $RESULT get changed when set via parameter expansion even though _top_of_script_pr() has already been called, presumably setting them when it's run. The reason this works is that _top_of_script_pr() is a ( subshelled ) function - I enclosed it in parens rather than the { curly braces } used for the others. Because it is called in a subshell, every variable it sets is locally scoped and as it returns to its parent shell those values disappear.

But when _more_important_function() sets $ACTION it is globally scoped so it affects _less_important_function()'s second evaluation of $ACTION because _less_important_function() sets $ACTION only via ${parameter:=expansion}.


Personal experience.

I use this format sometimes in my scripts to do ad-hoc over-riding of values, e.g. if I have:

$ cat script.sh
SOMETHING="${SOMETHING:-something}"; echo "$SOMETHING"; 

I can run:

$ env SOMETHING="something other than the default value" ./script.sh` 

without having to change the original default value of SOMETHING.

  • 1
    Fancy way of passing/overriding variables to/in a script :) Commented Mar 6, 2023 at 20:35

An interesting way of getting a single command-line parameter uses the $1, $2 ... scheme.

echo "$1 $2 $3"
echo "Second parameter: $Two"

Called with parameters: Won too tree

Result: Second parameter: too

Called with parameters: Five!

Result: Second parameter: default2

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .