1. Overview
Shell scripting involves a great deal of string manipulation and processing. Bash can handle string values enclosed in single or double quotes and even string values with no quotes at all. Furthermore, strings can be assigned to variables, saved in files, printed to the standard output, entered in shell scripts, and utilized in various other ways.
In this tutorial, we’ll focus on using double quotes in Bash. In addition, we’ll see some examples where double quoting is necessary.
2. Basic Use
Double quotes in Bash enclose string values. Double quotes preserve all characters inside them, with some exceptions:
- $
: used in variable interpolation and command substitution - ` <grave-accent>: used in command substitution
- \
: escapes special characters - ! <exclamation-mark>: performs history expansion, when enabled
When we enter a command in the terminal or run a shell script, Bash breaks the input into words and operators. In this effort, Bash uses the characters stored in the IFS variable. The default value of IFS contains three characters:
- space: separates words
- tab: similar to space, separates words
- newline: separates lines, like in multi-line shell script
This means that Bash breaks a string value that contains the above characters into words. Double quotes prevent word splitting and forces Bash to interpret the enclosed characters as a single string value.
To verify this fact, we’ll try to assign a sentence to a shell variable without quotes:
$ msg=Hello World of Linux
Command 'World' not found, did you mean:
command 'world' from snap world (4.0)
See 'snap info <snapname>' for additional versions.
As we can see, the assignment of the Hello World of Linux string value to the msg shell variable failed because of word splitting. Let’s try again with quotes:
$ msg="Hello World of Linux"
$ echo $msg
Hello World of Linux
Indeed, this time the assignment succeeded, because Bash treated the assigned value as a single string value.
3. Variable Interpolation
The $ character is used as a prefix for variable interpolation or expansion. Specifically, we prefix the name of a parameter with the $ character to perform the expansion.
In addition, double quotes enable the expansion of parameters:
$ msg="Hello $USER"
$ echo $msg
Hello ubuntu
Indeed, the USER shell variable was expanded inside the double quotes. As a result, the shell printed the logged-on user’s username.
A key point here is that variable interpolation isn’t feasible within single quotes:
$ msg='Hello $USER'
$ echo $msg
Hello $USER
As we expected, using single quotes resulted in printing the parameter name instead of its value.
Interestingly, we can disable variable interpolation inside double quotes as well, if we use the *\* escape character as a prefix to $:
$ msg="Hello \$USER"
$ echo $msg
Hello $USER
Again, as we anticipated, Bash printed the literal value of the string and no variable interpolation occurred.
4. Command Substitution
Similarly to variable interpolation, we can perform command substitution within double quotes:
$ msg="Date: $(date)"
$ echo $msg
Date: Wed Jul 26 16:24:16 EEST 2023
Here, the date command was executed before the assignment, and its value was assigned successfully to the msg variable. Let’s try the same with the ` character:
$ msg="Date: `date`"
$ echo $msg
Date: Wed Jul 26 16:27:34 EEST 2023
Same as before, Bash performed a command substitution of the date command, despite the double quotes. Again, this isn’t possible with single quotes:
$ msg='Date: $(date)'
$ echo $msg
Date: $(date)
As we expected, unlike double quotes, single quotes preserved the literal value of the enclosed characters, thus preventing command substitution.
5. Passing Parameters to Functions
Passing parameters to shell scripts or functions can be challenging when the parameters contain spaces, tabs, or newlines.
To examine this case, we’ll create a small function that counts and prints its input parameters one by one:
$ function countparams() {
> echo $#
> for p in "$@"; do
> echo $p
> done
> }
The countparams() function first outputs the $# special variable that holds the number of input parameters. Then, it loops through the input parameters using the $@ special variable and prints their values to the standard output.
Let’s try the function with an unquoted string:
$ countparams Hello World of $(uname)
4
Hello
World
of
Linux
As we can see, the countparams function interpreted its input as four parameters. This means that Bash split the string value that we entered into four words. Moreover, the uname command was successfully substituted with its output.
Next, let’s use single quotes:
$ countparams 'Hello World of $(uname)'
1
Hello World of $(uname)
This time, Bash interpreted the input string as a single parameter, which is what we wanted in the first place. Nevertheless, since we used single quotes, no command substitution occurred. As a result, the function printed $(uname) instead of Linux.
Finally, let’s use double quotes to disable word splitting and enable command substitution:
$ countparams "Hello World of $(uname)"
1
Hello World of Linux
By using double quotes, we managed to pass the string value as a single parameter and perform the command substitution as well.
6. History Expansion
As we mentioned earlier, the ! history expansion operator can be used inside double quotes. This character allows us to re-execute a command from our session’s history by entering the first letters of this command immediately after the exclamation mark:
$ echo World
World
$ !ec
echo World
World
Here, we can see that Bash found the last echo command that we executed and ran it again. Double quotes support the ! operator:
$ echo World
World
$ echo "Hello $(!ec)"
echo "Hello $(echo World)"
Hello World
In this example, we used both command substitution and history expansion. First, we echoed the World string to the standard output, so that the command is recorded in our session’s history. Next, we echoed Hello $(!ec) inside double quotes. Bash expanded !ec to the echo World command, and then executed the command because it was enclosed in the $() operator.
7. Conclusion
In this article, we learned about the use of double quotes in Bash. First, we understood how Bash performs word splitting. Then, we saw how quotes disable word splitting for the quoted expression. Next, we learned how double quotes deal with several concepts:
- variable interpolation
- command substitution
- function parameters
- history expansion
In conclusion, it’s necessary to use double quotes when performing variable interpolation, command substitution, or history expansion within a string value.