My grug brain can never remember the correct semantics of quoting commands and variables in a UNIX shell environment. Every time I work with a shell script or run some commands in a Docker compose file, I've to look up how to quote things properly to stop my ivory tower from crashing down. So, I thought I'd list out some of the most common rules that I usually look up all the time.
I mostly work with bash; so that's what I'll focus on. However, the rules should be similar for any POSIX compliant shell.
Single quotes vs double quotes vs backticks
Use single quotes when you don't want your shell to expand variables. For example:
In the previous snippet, the single quotes ensure that the value of the
doesn't get expanded by the shell and instead the literal name of the variable is used.
On the contrary, your shell will evaulate the variable if you use double quotes here:
In this case, the command prints the name of my host machine. Lastly, a backtick pair is
used to open a subshell and run some command. The following command allows you to check
out to the
HEAD-1th commit in Git:
git checkout `git rev-parse --short HEAD~1`
In the above command, first, the command within the backtick runs in a subshell and then
returns the result to the main shell. The
git checkout part of the command in the main
shell then uses the output value of the
git rev-parse --short HEAD~1 sub-command to
carry out the intended action.
While this works,
`...`is the legacy syntax for command substitution, required by only the very oldest of non-POSIX-compatible Bourne shells. A better alternative is to use the
git checkout $(git rev-parse --short HEAD~1)
When to quote variables
Quote if the variable can either be empty or contain any whitespace or special characters like spaces, backslashs or wildcards. Not quoting strings with spaces often leads to the shell breaking apart a single argument into many. Consider this command:
export x=some filename echo $x
This will print:
Ideally, this should've returned
some filename. You can fix this by quoting the value:
export x="some filename" echo $x
In the shell environment, the value of a variable is delimited by space. So if the value of your variable contains a space, it won't work correctly unless you quote it properly. This can also happen while accepting a value from a user and assigning it to a variable. For example:
read -p "Enter the name of a file: " file; cat $file
If the user provides a file name that contains a space or any special character like
/, the command above will behave unexpectedly. To ensure that the
is applied on a single file, wrap the
file variable with double quotes.
read -p "Enter the name of a file: " file; cat "$file"
Instead of double quotes, if you wrap the variable with single quotes, the command will
try to apply
cat on a file that's literally named
$file which is most likely not
what you want.