10

In a shell script, if I define a variable such as FOO=25, is there a difference between referencing it as $FOO$ and ${FOO}$?

  • 2
    You must not use the $ in the end! It will be treated as normal character and not as part of the variable name. – Byte Commander Oct 9 '15 at 11:15
16

In most situations both $var and ${var} are the same. (Note that you must not use a $ at the end!)

One example where you need curly braces are when you need to put a variable in a continuous string.

Example:

var=hel
echo ${var}lo

will output hello.

11

To answer your main question, ${foo} is called "parameter expansion". To be precise, the $ itself starts parameter expansion, the { } are actually optional according to the POSIX specification, but can be useful to indicate the end of the variable's name:

$ foo="bar"
$ echo $fooBaz   ## fails, no variable named $fooBaz exists

$ echo ${foo}Baz ## works, $foo is expanded and the string Baz is appended
barBaz

Basically, $foo and ${foo} are identical. Apart from cases like the above or when you are doing string manipulation, they are completely equivalent.

However, you shouldn't really use either of them. The rule of thumb is that, with very few exceptions, you should always use "$foo" or "${foo}" and never $foo or ${foo}. You should always quote your variables to avoid invoking the split+glob operator (more on that later). You certainly don't want $foo$. The final $ is irrelevant:

$ foo="bar"
$ echo "$foo$"
bar$

So, while unquoted variables are sometimes OK:

$ echo $foo
bar

They are usually not and should really be avoided:

$ if [ -n $foo ]; then echo empty; else echo "not empty"; fi ## fails
empty

$ if [ -n "$foo" ]; then echo empty; else echo "not empty"; fi ## works
not empty

Note that the brackets do not help here either:

$ if [ -n ${foo} ]; then echo empty; else echo "not empty"; fi  ## fails
empty

$ if [ -n "${foo}" ]; then echo empty; else echo "not empty"; fi ## works
not empty

When you use $foo or ${foo}, the shell will split the value saved in the variable on whitespace (this can be changed by setting the IFS variable to something else) into a list and then, each element of the list is treated as a glob pattern and expanded into any matching files or directories. This is known as the split+glob operator. To illustrate, consider a directory with two files:

$ ls -l
-rw-r--r-- 1 terdon terdon 0 Oct  9 18:16 file1
-rw-r--r-- 1 terdon terdon 0 Oct  9 18:16 file2

Now, let's set a variable to foo *:

$ foo="foo *"

What happens if we try to check if a file with that name exists?

$ if [ -e $foo ]; then echo "file exists"; else echo "no such file"; fi
file exists

The variable was split into foo and * and, since * is a wildcard that matches any string, the shell tells you that a file called foo * exxists. However, if we quote it correctly, this doesn't happen:

$ if [ -e "$foo" ]; then echo "file exists"; else echo "no such file"; fi
no such file

That was a trivial example to illustrate the point. Imagine if I had used rm instead of echo though.

So, first rule: always quote your variables. You can use either "$foo" or "${foo}" but quote it either way. For more detail on using variables safely, have a look at these posts:

  • I didn't want to edit your otherwise excellent answer, but shouldn't $ var="foo *" be $ foo="foo *"? You don't use var anywhere. – Joe Oct 17 '15 at 13:41
  • @Joe oh, good grief! Yes, of course it should, thanks for pointing it out. Feel free to fix such mistakes by suggesting an edit, by the way. That sort of thing is very much encouraged, precisely to avoid silly errors like this one. – terdon Oct 17 '15 at 13:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.