When do we need curly braces around shell variables?

302,457

Solution 1

In this particular example, it makes no difference. However, the {} in ${} are useful if you want to expand the variable foo in the string

"${foo}bar"

since "$foobar" would instead expand the variable identified by foobar.

Curly braces are also unconditionally required when:

  • expanding array elements, as in ${array[42]}
  • using parameter expansion operations, as in ${filename%.*} (remove extension)
  • expanding positional parameters beyond 9: "$8 $9 ${10} ${11}"

Doing this everywhere, instead of just in potentially ambiguous cases, can be considered good programming practice. This is both for consistency and to avoid surprises like $foo_$bar.jpg, where it's not visually obvious that the underscore becomes part of the variable name.

Solution 2

Variables are declared and assigned without $ and without {}. You have to use

var=10

to assign. In order to read from the variable (in other words, 'expand' the variable), you must use $.

$var      # use the variable
${var}    # same as above
${var}bar # expand var, and append "bar" too
$varbar   # same as ${varbar}, i.e expand a variable called varbar, if it exists.

This has confused me sometimes - in other languages we refer to the variable in the same way, regardless of whether it's on the left or right of an assignment. But shell-scripting is different, $var=10 doesn't do what you might think it does!

Solution 3

You use {} for grouping. The braces are required to dereference array elements. Example:

dir=(*)           # store the contents of the directory into an array
echo "${dir[0]}"  # get the first entry.
echo "$dir[0]"    # incorrect

Solution 4

You are also able to do some text manipulation inside the braces:

STRING="./folder/subfolder/file.txt"
echo ${STRING} ${STRING%/*/*}

Result:

./folder/subfolder/file.txt ./folder

or

STRING="This is a string"
echo ${STRING// /_}

Result:

This_is_a_string

You are right in "regular variables" are not needed... But it is more helpful for the debugging and to read a script.

Solution 5

Curly braces are always needed for accessing array elements and carrying out brace expansion.

It's good to be not over-cautious and use {} for shell variable expansion even when there is no scope for ambiguity.

For example:

dir=log
prog=foo
path=/var/${dir}/${prog}      # excessive use of {}, not needed since / can't be a part of a shell variable name
logfile=${path}/${prog}.log   # same as above, . can't be a part of a shell variable name
path_copy=${path}             # {} is totally unnecessary
archive=${logfile}_arch       # {} is needed since _ can be a part of shell variable name

So, it is better to write the three lines as:

path=/var/$dir/$prog
logfile=$path/$prog.log
path_copy=$path

which is definitely more readable.

Since a variable name can't start with a digit, shell doesn't need {} around numbered variables (like $1, $2 etc.) unless such expansion is followed by a digit. That's too subtle and it does make to explicitly use {} in such contexts:

set app      # set $1 to app
fruit=$1le   # sets fruit to apple, but confusing
fruit=${1}le # sets fruit to apple, makes the intention clear

See:

Share:
302,457
New User
Author by

New User

Updated on July 13, 2022

Comments

  • New User
    New User almost 2 years

    In shell scripts, when do we use {} when expanding variables?

    For example, I have seen the following:

    var=10        # Declare variable
    
    echo "${var}" # One use of the variable
    echo "$var"   # Another use of the variable
    

    Is there a significant difference, or is it just style? Is one preferred over the other?

  • Spencer Rathbun
    Spencer Rathbun over 12 years
    {} is known as brace expansion. ${} is known as variable expansion. They do different things. I'd upvote you except for the no expansion bit.
  • SiegeX
    SiegeX over 12 years
    @NewUser "So other than arrays it is not really required" Not so, the braces are necessary for PARAMETER EXPANSION, a very useful construct in scripting. I've seen many sed and awk scripts that can be replaced with a bit of parameter expansion.
  • L0j1k
    L0j1k over 9 years
    @caffinatedmonkey $() is used to execute a command, such that md5sum=$(md5sum foo.bin) will store the output of md5sum foo.bin in the variable md5sum, now accessible using ${md5sum}. Also, +1 and many more in spirit to OP for mentioning that it's good practice to be explicit!
  • Adrian Günter
    Adrian Günter over 8 years
    @L0j1k Speaking of explicitness, I find it important to mention that $() executes its command from a subshell.
  • karatedog
    karatedog over 8 years
    I thought I understood curly braces then, but I have just met this: seq ${1:-20} which is the same as seq 1 20. Is there any difference? (even in execution method?)
  • Olivier Dulac
    Olivier Dulac over 7 years
    I was about to ask a question here about: is there any drawback (performance? as it may think it have to do some special evaluation) of using curly-braces everywhere? In my scripts I always write: "${var}" instead of "$var" ... because I think it's easier to notice the var name, and because I can be sure I won't be bitten by the "next elements may be considered being part of the name" problem.. but is there really no negative side effects (except the addition of 2 chars per use? ^^ )
  • Aaron
    Aaron over 7 years
    @karatedog ${1:-20} is a form of parameter expansion. Here it is not obvious because it mainly uses digits and arithmetic operators which trick us in thinking there is arithmetic involved, but it actually refers to the positional parameter $1, which if not defined will be replaced by a default value 20 (the syntax is ${variable:-default_value}).
  • Armali
    Armali about 6 years
    This works just as well without curly braces around the variables.
  • Jarvis
    Jarvis about 5 years
    I couldn't understand the first line dir=(*). As far as I know, dir is an in-built command to list directory contents (equivalent to ls -C -b). Could you please explain?
  • glenn jackman
    glenn jackman about 5 years
    In shell programming, commands and arguments must be separated from each other by whitespace. Here, you see the equal sign with no whitespace, meaning this is a variable assignment. dir is the name of the variable, and the parentheses are used to collect the filename expansion * into an array.
  • gsl
    gsl about 5 years
    You may want to fix the weel-known novel bit. Upvoted nevertheless.
  • hrzafer
    hrzafer over 4 years
    As a plus, many tools support syntax highlighting for ${MY_VAR}.
  • Roger Dahl
    Roger Dahl about 4 years
    It's good to be not over-cautious: I wonder what most people think. Use curly braces all the time so you don't forget them when they're needed, or use them only where needed, to improve readability.
  • codeforester
    codeforester about 4 years
    I think it is the lack of awareness that leads to programmers using curlies even when they are not needed. This ignorance is similar to the other common mistake of not using double quotes to prevent inadvertent word splitting or globbing. At the base of it, the reality is that programmers are not serious about shell scripting as much as other scripting languages like Python and Ruby.
  • Roger Dahl
    Roger Dahl about 4 years
    True, that. My pet peeve is that everyone seems to think that all variables should be all caps in shell scripts :)
  • Kevin
    Kevin about 3 years
    @Jarvis In this case the word dir has no significance other then as a variable receiving an assignment. You can see this by using foo as the variable. foo=(*); echo "${foo[2]}"
  • Haravikk
    Haravikk about 2 years
    I disagree with the "it's good to be not over-cautious" remark; it is absolutely better to be over-cautious. I'd much rather have a million unnecessary curly brackets than a mistake that breaks something, especially given how difficult it can be to find errors in shell scripts (unhelpful error messages, or no error at all).