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

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

What You'll Learn

  • The concept of 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

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. How do I use that result inside another command?
Linny-senpai: That is exactly what command substitution is for. When you write $(command), that part gets replaced by the command's output.
Lina: Replaced? What do you mean?
Linny-senpai: Let's see it in action. When you write $(date), the shell runs date first, swaps $(date) for its output, and only then runs 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's handy.
Linny-senpai: Right. Once it's in a variable, you can reuse it as many times as you like — 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 =

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 treats today as a command name instead.

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's that?
Linny-senpai: That's the older syntax for command substitution. It behaves almost the same as $(date). But $(...) is the recommended form today.
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

You only need to read backticks. When writing 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's a $(...) inside another $(...). How does that run?
Linny-senpai: It's processed from the inside out. First $(pwd) becomes the current path (say /home/user/myproject), then basename takes it and returns just the last part, myproject.

Inside-out flow

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

With backticks you'd have to escape the inner ones as \`. With $(...) you can nest directly.

5. Why You Should Quote It

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

5-1. What breaks without quotes

$ files=$(ls)
$ echo $files        # no quotes
Lina: The file list printed all on one line. The line breaks disappeared...
Linny-senpai: That's the unquoted trap. The result of $(...) gets split into separate words on spaces and newlines (word splitting). To keep newlines and spaces as-is, wrap it in double quotes.
$ 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 won't break
  • Newlines are preserved
  • An empty result won't make the argument vanish and cause an error

"Just quote it" 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 automatically removes the trailing newline from the output. That's 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's 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 disappears, which can cause unexpected behavior.

7. Mini Exercises

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

Lina: I've got the theory! I want to try it myself.
Linny-senpai: Great — here are three tasks. Try them in your terminal.

Task 1: Store the current user name in a variable called me and print it (use whoami).

Show hint

Use the name=$(command) form. Print with echo "$name".

Sample answer
$ me=$(whoami)
$ echo "I am $me"

Task 2: Print the sentence "The current directory is ..." with the output of pwd embedded.

Show hint

Use echo "... $(pwd) ..." and wrap it in double quotes.

Sample answer
$ echo "The current directory is $(pwd)"

Task 3: Print only the name of the current directory (the last part, not the full path) using nesting.

Show hint

Pass $(pwd) to basename: $(basename "$(pwd)").

Sample answer
$ echo "$(basename "$(pwd)")"

basename takes the path from pwd and returns only its last part.

8. 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)")"

Next Reading