When do we need curly braces around shell variables?
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:
New User
Updated on July 13, 2022Comments
-
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 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 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 over 9 years@caffinatedmonkey
$()
is used to execute a command, such thatmd5sum=$(md5sum foo.bin)
will store the output ofmd5sum foo.bin
in the variablemd5sum
, 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 over 8 years@L0j1k Speaking of explicitness, I find it important to mention that
$()
executes its command from a subshell. -
karatedog over 8 yearsI thought I understood curly braces then, but I have just met this:
seq ${1:-20}
which is the same asseq 1 20
. Is there any difference? (even in execution method?) -
Olivier Dulac over 7 yearsI 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 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 value20
(the syntax is${variable:-default_value}
). -
Armali about 6 yearsThis works just as well without curly braces around the variables.
-
Jarvis about 5 yearsI couldn't understand the first line
dir=(*)
. As far as I know,dir
is an in-built command to list directory contents (equivalent tols -C -b
). Could you please explain? -
glenn jackman about 5 yearsIn 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 about 5 yearsYou may want to fix the
weel-known novel
bit. Upvoted nevertheless. -
hrzafer over 4 yearsAs a plus, many tools support syntax highlighting for
${MY_VAR}
. -
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 about 4 yearsI 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 about 4 yearsTrue, that. My pet peeve is that everyone seems to think that all variables should be all caps in shell scripts :)
-
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 about 2 yearsI 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).