Command Substitution: Capturing Output with $(...)

Command Substitution: Capturing Output with $(...)

What you'll be able to do

  • Embed a command result in a sentence with `$(command)`
  • Store a command result in a variable with `VAR=$(command)`
  • Explain why you wrap it as `"$(...)"`, and how backticks differ

Prerequisites (read these first)

What You'll Learn

  • The idea behind command substitution
  • How to capture command output into a variable with $(command)
  • How $(...) differs from the older backticks `...`
  • Why you should wrap it as "$(...)" with quotes

Words used here

  • Variable: a named box that holds a value. Write the name and you get the contents.
  • Command substitution: a way to drop a command's output into a line as text. It is sometimes called capturing output.
  • Quotes: "..." are double quotes and '...' are single quotes.

Every command in this article — date, pwd, whoami, ls — only displays things. None of them deletes or edits a file, so a typo cannot damage your computer.

Quick Summary

  • Store output in a variableVAR=$(command)
  • Embed output in text → echo "Today is $(date)"
  • When in doubt, wrap it in double quotes: "$(...)"

1. What Is Command Substitution?

Conclusion: Command substitution runs a command and replaces $(...) with its output, inline.

Lina: Senpai, when I run date it prints today's date. I want to use that result inside another command. How do I do that?
Linny-senpai: That is exactly what command substitution is for. Write $(command) and that part gets replaced by the command's output.
Lina: Replaced? What does that mean?
Linny-senpai: Picture a fill-in-the-blank letter. You look up the date, write it into the blank, and then read the whole thing aloud.
Linny-senpai: With $(date), the shellAn interactive program that reads the commands you type and runs them. runs date first. It swaps $(date) for the output. Only then does it run the whole command.
$ echo "Today is $(date)"
Today is Fri Jun  5 12:00:00 JST 2026

How the replacement works

echo "Today is $(date)"
              ↓ run date first
echo "Today is Fri Jun 5 ... 2026"

The contents of $(...) turn into output-as-text before the outer command runs.

2. Capturing Output into a Variable

Conclusion: Use VAR=$(command) to store output in a variable. No spaces around the = sign.

2-1. The basic form

$ today=$(date +%Y-%m-%d)
$ echo "$today"
2026-06-05
Lina: The today variable now holds the date. That is handy.
Linny-senpai: Right. Once it is in a variable, you can reuse it as often as you like. Put it in a log file name, in a message, anywhere.
$ logfile="backup-$today.log"
$ echo "$logfile"
backup-2026-06-05.log

2-2. No spaces around =

A variable assignment must have no spaces around the = sign.

today = $(date)    # WRONG: shell looks for a command named "today"
today=$(date)      # correct

With spaces, the shell reads today as a command name. You then get command not found.

3. How It Differs from Backticks

Conclusion: Backticks do the same job, but $(...) nests cleanly and reads better. Prefer it.

Lina: Some articles wrap commands in backticks, like `date`. What is that?
Linny-senpai: That is the older syntax for command substitution. It behaves almost the same as $(date). Today $(...) is the recommended form.
Lina: Why is the newer one better?
# Old syntax (backticks)
$ echo "Today is `date`"

# New syntax (recommended)
$ echo "Today is $(date)"

Why $(...) is preferred

Aspect Backticks `...` $(...)
Nesting Hard (needs escaping) Works as-is
Readability Easy to confuse with ' Clear brackets
Quoting Quirky Straightforward

Understanding backticks is enough for reading older articles. When you write your own, stick to $(...).

4. Nesting Substitutions

Conclusion: You can put $(...) inside $(...). The inner one runs first and feeds the outer.

$ echo "$(basename $(pwd))"
myproject
Lina: There is a $(...) inside another $(...). How does that run?
Linny-senpai: It is processed from the inside out. First $(pwd) becomes the current pathA string that describes the location of a file or directory., say /home/user/myproject.
Linny-senpai: Then basename takes that and returns only the last part, myproject. basename is the command that strips a path down to its final name.

Inside-out flow

basename $(pwd)
         ↓ run pwd
basename /home/user/myproject
         ↓ run basename
myproject

With backticks, you would have to rewrite the inner ones as \`. That rewriting is called escaping, and it is fiddly.

With $(...) you can nest directly. That is its biggest advantage.

5. Why You Should Quote It

Conclusion: Wrapping it as "$(...)" keeps spaces and newlines intact as a single safe value.

5-1. Lina gets stuck: the newlines disappear

$ files=$(ls)
$ echo $files        # no quotes
Documents Downloads report.txt
Lina: The file list printed all on one line. The line breaks are gone. Did the variable get damaged?
Linny-senpai: Nothing is damaged. The newlines are still in there.
Lina: The contents survived? That is a surprise.
Linny-senpai: Yes. What broke is the way it was handed over. Without quotes, the result of $(...) is cut into separate words at every space and newline. That is called word splitting.
Linny-senpai: Then echo reprints those words with single spaces between them. That is why it looks like one line.
Lina: So it was the handover, not the contents. That makes sense now.
$ echo "$files"      # with quotes
Documents
Downloads
report.txt

5-2. When in doubt, quote it

As a rule, wrap substitution results in double quotes: "$(...)".

  • File names with spaces will not break
  • Newlines are preserved
  • An empty result will not make the argument vanish and cause an error

Making "quoteWrapping a string in quote marks (' or ") so it is treated as one single value, e.g. one with spaces in it. it when in doubt" a habit prevents most of the common accidents.

6. Common Beginner Pitfalls

Conclusion: Trailing newlines are stripped, and you can use variables inside $() freely.

6-1. Trailing newlines are stripped

$ count=$(ls | wc -l)
$ echo "There are $count files"
There are 3 files

Command substitution removes the trailing newline from the output on its own. That is why you can drop the number straight into a sentence.

6-2. Variables and arguments work inside $()

$ dir=/etc
$ echo "Files in $dir: $(ls "$dir" | wc -l)"
Files in /etc: 220

Inside $(...) it is just a normal command line. Variables, pipes, and even other substitutions all work.

6-3. Stay safe when the result is empty

$ result="$(grep "no such word" file.txt)"
$ echo "[$result]"
[]

When quoted, an empty search result simply prints [].

Without quotes the argument itself disappears. That is a common cause of unexpected behavior.

7. Mini Exercises

Conclusion: Three tasks — assign, embed, and nest — to practice the basics by hand.

Lina: I have the theory. I want to try it myself.
Linny-senpai: Good. Here are three exercises. Try them in your terminal.

Exercise 1: Store the current user name in a variable called me and print it in a sentence.

Show Hint 1 (Direction)

First run the command that reports your user name. Put the result in a box, then take it back out as part of a sentence.

Show Hint 2 (Command name)

The user name comes from whoami. The form for storing it is name=$(command). Print with echo.

Show Answer
$ me=$(whoami)
$ echo "I am $me"
I am lina

The name you see depends on your account.

Exercise 2: Print the sentence "The current directoryA container that organizes files. Same idea as a "folder" on Windows or macOS. is ..." with the output of pwd embedded.

Show Hint 1 (Direction)

No variable this time. Drop the command's output straight into the middle of a sentence.

Show Hint 2 (Command name)

Your location comes from pwd. Wrap the whole sentence in double quotes and insert $(pwd).

Show Answer
$ echo "The current directory is $(pwd)"
The current directory is /home/lina/myproject

The path you see depends on where you are.

Exercise 3: Print only the name of the current directory. That means the last part, not the whole path.

Show Hint 1 (Direction)

Two steps. First get the full path of where you are. Then take only the final name out of that path.

Show Hint 2 (Command name)

The full path comes from pwd. The final name comes from basename. Nest one $(...) inside another.

Show Answer
$ echo "$(basename "$(pwd)")"
myproject

basename takes the path from pwd and returns only its last part. Note that the inner $(pwd) runs first.

8. Review

Lina: Let me sum up. $(command) replaces that spot with the command's output.
Linny-senpai: Right. And when you want to keep the result, use VAR=$(command).
Lina: When I use the result, I wrap it as "$(...)". Without the quotes, word splitting breaks it.
Linny-senpai: That's it. Reading backticks is enough; write $(...) yourself.

9. Copy-Paste Templates

Conclusion: Templates for assigning, embedding, naming, and counting — keep them handy.

Handy patterns to keep

# Store output in a variable
VAR=$(command)

# Embed in a sentence (always double-quote)
echo "The result is $(command)"

# Build a dated file name
logfile="app-$(date +%Y%m%d).log"

# Count lines into a variable
count=$(ls | wc -l)

# Nest substitutions
name="$(basename "$(pwd)")"

Today's 3-Line Summary

  1. $(command) replaces that spot with the command's output
  2. To keep the result, write VAR=$(command). Never put spaces around the =
  3. When you use the result, wrap it as "$(...)", or spaces and newlines will split it

Next Reading

Share this article

Next steps