DEV Community

Cover image for Bash Variables: To quote, or not to quote...
Jimmy McBride
Jimmy McBride

Posted on

Bash Variables: To quote, or not to quote...

echo "$VARIABLE"

Should you ALWAYS wrap your variables in quotes??? Some would say, "Yes! Absolutely, always wrap your variables in quotes. Just to be safe!" Well, I say, "You do you, dawg".

Fortunately, I'm not just going to leave you hanging there. Let's explore the differences between wrapping our variables in quotes and see what the differences are. Then, we can determine for ourselves, when is the best time to use quotes around our variables. All the time, or some of the time? Decide for yourself!

$HOME and $PATH

echo $HOME
home/jimmy

echo "$HOME"
home/jimmy
Enter fullscreen mode Exit fullscreen mode

Well, it doesn't seem like there's much of a difference here! Let's create a variable with some spaces in it and see what happens.

NAME="Jimmy     McBride"

echo $NAME
Jimmy McBride

echo "$NAME"
Jimmy     McBride
Enter fullscreen mode Exit fullscreen mode

Now, we're getting somewhere! It seems like if we have more than 1 empty space in a variable and if those spaces are important we need wrap our variable in quotes!

Rule of thumb: If your variable contains more than 1 consecutive white space and that white space is important for any reason then you DEFINITELY want to wrap your variable in quotes.

Let's create a variable with a wildcard (*) and see what happens...

NAME="Jimmy McBride *"

echo $NAME
Jimmy McBride bin calc Desktop Documents Downloads Games indicator-bulletin Music Pictures Postman Public Templates Videos
Enter fullscreen mode Exit fullscreen mode

Uh-oh! Looks like, instead of printing out "Jimmy McBride *" It printed out "Jimmy McBride" plus all of our files in our home folder. That's most likely not what we wanted.

NAME="Jimmy McBride *"

echo "$NAME"
Jimmy McBride *
Enter fullscreen mode Exit fullscreen mode

Now that looks a whole lot better!

Rule of thumb: If you have a wildcard character (*) in your code and you want it to act as a regular character you DEFINITELY want to wrap your variable in quotes. However, if you intend for it to be and act as an actual wildcard, then you should NOT wrap your variable in quotes.

Let's play around a bit with putting variables in quotes...

NAME="Jimmy McBride"

echo $NAME $HOME
Jimmy McBride /home/jimmy

echo $NAME       $HOME
Jimmy McBride /home/jimmy

echo "$NAME       $HOME"
Jimmy McBride       /home/jimmy

echo $NAME * $HOME
Jimmy McBride bin calc Desktop Documents Downloads Games indicator-bulletin Music Pictures Postman Public Templates Videos /home/jimmy

echo "$NAME" * "$HOME"
Jimmy McBride bin calc Desktop Documents Downloads Games indicator-bulletin Music Pictures Postman Public Templates Videos /home/jimmy

echo "$NAME * $HOME"
Jimmy McBride * /home/jimmy
Enter fullscreen mode Exit fullscreen mode

Conclusion

If you variable doesn't contain consecutive white spaces that are important or if you have a wild card symbol that you don't want to behave as a wildcard, you definitely want to wrap you variable in quotes.

If you have a variable with a wildcard and you want it to behave as a wildcard, then you definitely want to wrap that puppy in quotes.

If the variable you are calling doesn't have important consecutive white spaces or contain a wildcard character then it doesn't seem to make a difference whether or not you use quotes or not. In that situation, especially when I know what the variables are, I would save my self a few keystrokes by not adding quotes. However, if you are ever uncertain when using a variable, wrapping it in quotes just to be safe might be a really good idea!

What are your thoughts? Did I miss anything? What's your opinion? Let me know in the comments! Thanks! πŸ˜„

Top comments (7)

Collapse
 
ahferroin7 profile image
Austin S. Hemmelgarn

There's one really big one you missed:

If you need the shell to treat each 'word' of your variable as separate arguments for a command, you need to not quote the variable when expanding it.

This also happens to explain the behavior surrounding whitespace:

ITEMS="foo   bar"

# This passes two arguments to `echo`, 'foo' and 'bar'
echo $ITEMS

# This passes one argument to `echo`, 'foo   bar'
echo "$ITEMS"

This is also one of the big reasons that you almost always see variables quoted when doing expansion for conditionals, and almost never see them quoted for expansion as part of a for loop. The first case (conditionals) almost always wants the contents of the variable as a single argument, while the second almost always wants each item to be a separate argument.

Collapse
 
jimmymcbride profile image
Jimmy McBride

That's actually a super good point! I'm going to update this very soon. Thank you!

Collapse
 
andyneff profile image
Andy Neff • Edited

My opinion, you should always quote. And only exclude quotes in the "special" scenarios mentioned. Not the other way around. In my experience, if you are always asking the question "do I need to add quotes here", and only add them when you think yes, down the road you'll find out you should have, especially when someone not you on Windows or macos uses your script (they love spaces in filenames). Just get into the habit. It makes safer code. (I can't think of an easy example without eval offhand)

x="ok; ls /"
eval echo ${x}

Now you tried to be safe with the eval by adding the echo but now you have an arbitrary execution by accident. If you just got in in the habit of always using the quotes, then you would be better off

eval 'echo "${x}"'
eval "echo '${x}'"
# Both work the same, slightly different expansion order

Going back to the case of echo $NAME, how can I say "I want to explicitly support wildcard/home dir expansion and still use quotes?"

NAME="Jimmy McBride *"
NAMES=(${NAME})
echo "${NAMES[@]}"
Jimmy McBride bin calc Desktop Documents Downloads Games indicator-bulletin Music Pictures Postman Public Templates Videos

Now the code clearly show you mean to expand NAME, and you can use the array NAMES with quotes still.

As a side note, on the subject of "to curly or not to curly", I say always curly

x=100
echo $x2
echo "${x}2"

Instead of discovering you need to add {}, if you always add them, your script will just work.

I'll end with one of my favorite bashisms.

REAL_CWD="$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)"

A sane person would say of course my directory doesn't have spaces in it. A windows person would say of course my folder has spaces in it.

Update:

I should add, the exception that is the rule is [[]]. While you should always use quotes in [] statements, you should probably never use them in [[]] statements, as they are more advanced, and don't need the quotes. In face, the quotes are literal, and can give you the wrong answer.

Collapse
 
jimmymcbride profile image
Jimmy McBride

Wow, nice work man! Yeah, this definitely changed my mind a little bit and I'm going to make sure to put in those quotes and curly's in my code.

The main reason I made this blog because I knew that quotes were considered best practice, but didn't quite understand why on a deep level. So I thought I'd make a provocative post on bash quotes, let the reader know what I know and let the onslaught of comments coming in teach me something new. This is exactly what I was looking for. So, thank you!

Collapse
 
tsvi profile image
Tsvi Mostovicz

You forgot one more. When quoting, the value is considered a string. Otherwise it depends on the contents.

This is important for comparison operators as the comparison operators are different for integers (-eq, -gt, -lt, ...) and for strings (==, !=).

So quoting in a comparison makes it less error prone as you know you have a string and can use == to compare.

Collapse
 
gypsydave5 profile image
David Wickes

In the words of Ellen Ripley:

I say we take off and quote every variable in the Bash script. It’s the only way to be sure.

Collapse
 
togakangaroo profile image
George Mauer

I mean... When it's a variable that kind of implies that we shouldn't make assumptions about it's contents. You know, because it's variable.