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 variable →
VAR=$(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.
date it prints today's date. How do I use that result inside another command?$(command), that part gets replaced by the command's output.$(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
today variable now holds the date! That's handy.$ 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.
`date`. What's that?$(date). But $(...) is the recommended form today.# 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
$(...) inside another $(...). How does that run?$(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
myprojectWith 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
$(...) 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.
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)")"