20  20. Single Quotes vs. Double Quotes

You have already used both kinds of quotes to keep text together. Now that you know about environment variables, you can understand the important difference between them. Quotes appear in almost every real command, including the commands AI tools write for you, so it pays to read them correctly.

20.1 Recap: both kinds keep text together

Both "double quotes" and 'single quotes' keep spaces and special characters together as one piece of text (see Writing to Files):

echo "Hello     World"
echo 'Hello     World'

Output:

Hello     World
Hello     World

So far they look identical. The difference shows up as soon as the text contains a $.

20.2 The difference: $ works only inside double quotes

  • Inside double quotes, the shell still looks for $. It replaces $NAME (or ${NAME}) with the variable’s value, and $(command) with the output of that command. Everything else is kept as typed.
  • Inside single quotes, nothing is changed. The text is literal: exactly what you typed, character for character.

Here is Maria on her Mac:

echo "Home: $HOME"
echo 'Home: $HOME'

Output:

Home: /Users/maria
Home: $HOME
price=20
echo "Price: $price dollars"
echo 'Price: $price dollars'

Output:

Price: 20 dollars
Price: $price dollars

$(command) is called command substitution: the shell runs the command and puts its output into the text. It also works only inside double quotes (or with no quotes at all):

cd ~/Documents/bash-tutorial-files
echo "I am in $(pwd)"
echo 'I am in $(pwd)'

Output:

I am in /Users/maria/Documents/bash-tutorial-files
I am in $(pwd)

A simple way to remember: single quotes mean “say exactly this”; double quotes mean “say this, but fill in the variables first.”

"double quotes" 'single quotes'
Keep spaces and >, ;, *, ~ … as plain text yes yes
$NAME and ${NAME} replaced with the variable’s value kept as typed
$(command) replaced with the command’s output kept as typed
A backslash \ before $ or " makes it a plain character kept as typed

20.3 When a $ should stay a $

Money amounts are a classic surprise:

echo "The total is $5"

Output:

The total is

The shell read $5 as a variable (a special one that scripts use, see Bash Scripts). It’s empty here, so it disappeared. Two fixes:

echo 'The total is $5'
echo "The total is \$5"

Output:

The total is $5
The total is $5

Inside double quotes, a backslash (\) in front of $ “escapes” it: it tells the shell to treat the next character as an ordinary character. The same rule matters for Git commit messages you will write later: use git commit -m 'Fix $10 discount bug', not double quotes.

20.4 Quotes inside quotes

  • To include an apostrophe, use double quotes: echo "It's Maria's laptop"
  • To include double quotes, use single quotes: echo 'He said "hi"'
  • To include a double quote and a $ inside double quotes, escape them with backslashes:
echo "She said \"wow\" and paid \$20"

Output:

She said "wow" and paid $20

A single quote can never appear inside single quotes (not even with a backslash), so switch to double quotes when your text contains an apostrophe.

Stuck at a >, quote>, or dquote> prompt?

If your quotes don’t match, as in echo 'It's raining' (three single quotes), the shell waits for you to close the quote. Git Bash shows a > prompt; zsh on a Mac shows quote> or dquote>. Press Ctrl+C to cancel, then retype the command with matching quotes: echo "It's raining".

20.5 No quotes: spaces, wildcards, and ~

Without quotes, the shell does more work before it runs a command:

  • it splits the line into separate words at the spaces,
  • it expands wildcards such as * into matching file names (see Wildcards and Pipes),
  • it replaces a ~ at the start of a word with your home directory.

Quotes (of either kind) turn all of this off. In the notes practice folder:

echo Files: *.txt
echo "Files: *.txt"

Output:

Files: ideas.txt meeting-notes.txt
Files: *.txt

20.5.1 Always quote variables that hold file names

In Bash, even the value of an unquoted variable is split at spaces. Suppose a folder contains a file named Q3 report.txt:

file="Q3 report.txt"
cat $file

zsh (the Mac’s default shell) does not split variables this way, so this unquoted command happens to work at the Mac prompt. It fails as soon as the same command runs in Bash, for example inside a Bash script, which is why you should quote anyway.

Output:

cat: Q3: No such file or directory
cat: report.txt: No such file or directory

Bash split the value into two words, so cat looked for two files, Q3 and report.txt.

The fix works everywhere: put the variable in double quotes, cat "$file". Double quotes keep the value together while still filling it in.

20.5.2 ~ doesn’t work inside quotes

ls "~/Documents" fails with “No such file or directory”, because inside quotes ~ is just a character (see Files, Folders, and Paths). To combine your home folder with a name that contains spaces, use $HOME inside double quotes, or leave the ~/ outside the quotes:

ls "$HOME/My Projects"
ls ~/"My Projects"

20.6 Rules of thumb

  1. Text that must stay exactly as typed (prices, commit messages, passwords in examples, search patterns): use single quotes. They are the safe choice for anything containing $, !, `, or \.
  2. Text that should include a variable or a command’s output: use double quotes: echo "Backup of $HOME finished".
  3. Always put variables that hold file names or paths in double quotes: "$file", "$HOME/My Projects".
  4. Don’t put ~ inside quotes. Use "$HOME/..." instead.
  5. Not sure what the shell will do? Put echo in front of the command to see the words it would receive.

20.7 Why this matters when AI writes your commands

As of Oct 6, 2026 · Official docs: How Claude Code works

Claude Code runs shell commands as part of its work (for example to run tests or use Git), and chat assistants give you commands to paste. Quotes decide what those commands actually do, so read them carefully. For example, here is the >> technique from Environment Variables, used to add a PATH line to your startup file:

echo 'export PATH="$HOME/bin:$PATH"' >> ~/.zshrc

The outer single quotes make everything inside literal, so the file receives exactly export PATH="$HOME/bin:$PATH", with the $ signs still in it. The variables are filled in later, each time a new terminal reads the file, which is what you want. (With outer double quotes, the inner double quotes would end the text early, and $HOME and $PATH would be filled in right away.)

Quoting rules are also one reason commands don’t move freely between shells: PowerShell and CMD on Windows quote differently from Bash and zsh. When you ask an AI for a command, say which shell you use (“zsh on a Mac” or “Git Bash on Windows”).

When you type commands interactively, Bash and zsh treat ! as a shortcut for recalling earlier commands (history expansion; for example, !! means “the previous command”). This happens even inside double quotes; only single quotes reliably protect a !.

  • Git Bash: echo "Hello!" works, because a ! right before the closing quote or a space is left alone. But echo "Wow!Great" fails with bash: !Great: event not found.
  • Mac (zsh): echo "Hello!" leaves you at a dquote> prompt (press Ctrl+C), and echo "Wow!Great" fails with zsh: event not found: Great.
  • Both: echo 'Hello!' and echo 'Wow!Great' work.

Scripts are not affected: history expansion only happens in commands you type at the prompt. (Putting a backslash before the ! inside double quotes behaves differently in Bash and zsh, so single quotes are the simple, reliable fix.)

Practice Questions

Easy

Question 1 · True or false

Both single quotes and double quotes keep multiple spaces between words.

True. Both kinds of quotes keep the text inside them together as one piece, spaces included. Their difference is in how they treat $.

Question 2 · Multiple choice

In which of these commands is $HOME replaced by the path of your home directory?

  1. echo '$HOME'
  2. echo "$HOME"
  3. echo '"$HOME"'
  4. None of them

b. Inside double quotes, $HOME is replaced by its value. In a, the single quotes make it literal. In c, the outer quotes are single quotes, so everything inside, including the double quotes, is printed as typed: "$HOME".

Question 3 · Predict the output

What does echo 'Hello $USER' print?

Hello $USER, exactly as typed. Single quotes make the text literal, so the shell does not replace $USER.

Question 4 · Fill in the blank

Inside ______ quotes, the shell changes nothing: every character, including $, is kept exactly as typed.

single quotes.

Question 5 · Multiple choice

Which command prints It's raining correctly?

  1. echo 'It's raining'
  2. echo "It's raining"
  3. echo 'It\'s raining'
  4. echo It's raining

b. An apostrophe is fine inside double quotes. In a and c, the apostrophe ends the single-quoted text early (a backslash doesn’t help inside single quotes), and in d the apostrophe starts a quote that never ends. Each of those leaves the shell waiting at a > or quote> prompt.

Medium

Question 6 · Predict the output

Sam (Git Bash, home folder /c/Users/sam) runs:

echo "My home is $HOME"
echo 'My home is $HOME'

What does he see?

My home is /c/Users/sam
My home is $HOME

Question 7 · Predict the output

item="laptop"
echo "Item: $item"
echo 'Item: $item'
echo "Item: ${item}s"
Item: laptop
Item: $item
Item: laptops

The braces in the last line mark where the variable name ends, so the s is added after the value.

Question 8 · Find the bug

echo "The ticket costs $5" prints The ticket costs with no price. Why? Give two ways to fix it.

Inside double quotes the shell treats $5 as a variable (a special one used by scripts), which is empty here, so it disappears. Fixes: echo 'The ticket costs $5' (single quotes) or echo "The ticket costs \$5" (escape the $ with a backslash).

Question 9 · Write the command

Write two different echo commands that print exactly:

She said "yes"
echo 'She said "yes"'
echo "She said \"yes\""

Single quotes keep the double quotes as plain characters; inside double quotes you escape each " with a backslash.

Question 10 · Write the command

The command date +%A prints the day of the week (for example Tuesday). Use command substitution to print a line such as Today is Tuesday.

echo "Today is $(date +%A)"

$(date +%A) runs the command and puts its output into the text. Double quotes (or no quotes) are needed; with single quotes you would just see Today is $(date +%A).

Question 11 · Find the bug

Maria types ls "~/Documents" and gets “No such file or directory”, even though her Documents folder exists. Explain, and give two commands that work.

~ is replaced by the home folder only when it is not inside quotes. Here, ls looks for a folder literally named ~. Working versions: ls ~/Documents and ls "$HOME/Documents" ($HOME is filled in inside double quotes).

Question 12 · Find the bug

In Git Bash, Sam types:

cd $HOME/My Projects

He gets an error. What’s wrong, and how should he type it?

Without quotes, the space splits the path into two words, $HOME/My and Projects, so cd doesn’t receive the full folder name (Bash reports an error such as “too many arguments”). Quote the whole path with double quotes, so that $HOME is still filled in:

cd "$HOME/My Projects"

(cd ~/"My Projects" also works.)

Question 13 · Predict the output

In the notes practice folder (which contains ideas.txt and meeting-notes.txt), what do these print?

echo *.txt
echo '*.txt'
ideas.txt meeting-notes.txt
*.txt

Without quotes, the shell expands the wildcard *.txt into the matching file names. Quotes turn wildcard expansion off.

Hard

Question 14 · Scenario

An AI assistant suggests this command for a commit message:

git commit -m "Update prices: now $9.99"

What message will actually be saved, and how should the command be written?

Inside double quotes, $9 is treated as a (special, empty) variable, so the message becomes Update prices: now .99. Use single quotes so that the text is literal:

git commit -m 'Update prices: now $9.99'

(Escaping also works: "Update prices: now \$9.99".)

Question 15 · Long answer

Explain why this command uses single quotes around the whole export ... line, and what would go wrong if you used double quotes on the outside instead.

echo 'export PATH="$HOME/bin:$PATH"' >> ~/.zshrc

The goal is to write the line exactly as shown into ~/.zshrc, including the $HOME and $PATH variable names and the inner double quotes. Single quotes make everything inside literal, so that’s what happens. The variables are then filled in each time a new terminal reads the file, using the PATH of that moment.

With outer double quotes, the inner " characters would end the quoted text early, and $HOME and $PATH would be replaced immediately with their current values. The file would get one long, fixed list of folders (and no quotes around it), instead of a line that builds on whatever PATH is when the terminal starts.

Question 16 · Scenario

A Bash script contains:

file="Q3 report.txt"
cat $file

It prints two “No such file or directory” errors, although Q3 report.txt exists. Maria says the same two lines work fine when she types them into her Mac’s Terminal. Explain both observations and give the fix.

Bash splits the value of an unquoted variable at spaces, so cat receives two arguments, Q3 and report.txt, and neither file exists. Maria’s Terminal runs zsh, which does not split variable values this way, so the unquoted version happens to work there. The fix works in every shell: cat "$file". Always put variables that hold file names in double quotes.

Question 17 · Scenario

On her Mac, Maria types echo "Deployment done!". The terminal shows dquote> and waits. What is going on, how does she get out, and what should she type instead?

In zsh, ! is special (history expansion) even inside double quotes, and the combination !" messes up the quoting, so zsh thinks the double quote was never closed and waits for more input. She should press Ctrl+C to cancel and then use single quotes, which always protect !: echo 'Deployment done!'.

Question 18 · Long answer

Give three rules of thumb for choosing between single quotes, double quotes, and no quotes, each with a short example.

A good answer includes three of these:

  1. Use single quotes for text that must stay exactly as typed, especially if it contains $, !, or \: git commit -m 'Fix $10 discount bug'.
  2. Use double quotes when the text should include a variable or a command’s output: echo "Backup of $HOME finished".
  3. Always double-quote variables that hold file names or paths: cat "$file", cd "$HOME/My Projects".
  4. Leave ~ and wildcards unquoted when you want the shell to expand them: ls ~/Documents/*.txt, and quote them when you don’t: echo '*.txt'.

Question 19 · Predict the output

name="Sam"
echo "Hi $name, it's \$10 for 'Pro'"
Hi Sam, it's $10 for 'Pro'

Inside double quotes, $name is filled in, the backslash turns \$ into a plain $, and single quotes and apostrophes are ordinary characters.

© 2025-2026 Y. Rosenthal. All rights reserved.