Learn › Linux Foundations › Bash Shell Environment
echo - a hands-on Linux lab on a real virtual machine.
Let one command find a value and drop it straight into your command line with $(command). Inline a command output into a sentence, capture it into a variable and reuse it, feed one command result to another, and quote the substitution to keep multi-word output whole. Built on echo plus live commands, so the fixed wrapping words are byte-stable and only the live value (weekday, hostname, date) varies per machine.
So far, every command you have typed said exactly what you meant, letter for letter. You wrote the filename, you wrote the number, you wrote the word. But real work is full of values you do not know yet: today's date, the name of this machine, how many files are in a folder. You cannot type what you do not know.
So you let one command find the answer, and you drop that answer straight into the next command. The shell runs the inner command first, takes whatever it printed, and slots it right into the line where you asked. It is called command substitution, and once you see it, you will use it every day.
The black boxes in this lesson are a practice terminal: a safe sandbox that only checks the one command each step teaches, so you cannot break anything. A couple of the outputs below come from the live machine, like today's weekday and this computer's name, so those exact words will differ when you run them for real. What never changes is the command you type. That is the lesson.
Command substitution has one job: run a command, capture what it printed, and put that text into your command line. The syntax is a dollar sign and a pair of round brackets with a command inside: $(command).
Read $(date) out loud as "the output of date". Whatever date would have printed, that text takes the place of the whole $(date) in your line. The shell does the swap before it runs the rest of the command, so by the time your real command runs, the $(...) is already gone, replaced by its result.
You have met echo already: it prints back whatever you hand it. Pair echo with a substitution and you can watch the swap happen. Ask the shell to print a sentence with today's weekday baked into it:
echo "Today is $(date +%A)"
prompt: student@linuxcamp:~$ answer: echo "Today is $(date +%A)" output: Today is Monday hint: Type echo, a space, then the sentence in double quotes with $(date +%A) inside: echo "Today is $(date +%A)"
The day you see is not always Monday. date +%A asks the real machine for the real day of the week, so it prints whatever today actually is: Tuesday, Saturday, whatever. The word Today is in front never changes, because you typed it; only the part $(date +%A) produced varies. That is exactly the point of a substitution: the fixed text is yours, the live part comes from the command.
Trace what happened. The shell saw $(date +%A), ran date +%A on its own first, and got back one word, the weekday. It deleted the whole $(date +%A) from your line and dropped that word in its place, so echo actually received Today is Monday and printed it. The substitution ran before echo ever saw the line. That order, inner command first, is the heart of every example that follows.
The idea is old. The original Bourne shell in the late 1970s already let you inline a command. You wrapped it in backticks, the slanted quote on the same key as ~. So ` date did the very same swap that $(date)` does now. Backticks still work today, so you will see them in old scripts.
The modern form $(...) was added later for one good reason: backticks are hard to nest and easy to misread as ordinary quotes. $(...) reads cleanly and nests without pain, so it is the form every current guide teaches, and the form you will write. Just recognise backticks when you meet them in someone else's script.
Printing a substitution is useful, but the real power is keeping the result to use again. Remember from the variables lesson that name=value stores a value under a name with no spaces around the =. Put a substitution on the right of that = and you store what the command printed.
The inner command here is a small pipeline: ls lists the files, and wc -l counts the lines it produced, which is the number of files. Wrap that in $(...) and the count lands in a variable called count, ready to reuse:
count=$(ls | wc -l)
Then print a sentence that uses it. In the sandbox this folder holds three files, so the count comes back as 3:
echo "There are $count files"
prompt: student@linuxcamp:~$ answer: count=$(ls | wc -l) output: hint: Assign with no spaces around the equals, and put the pipeline in $(...): count=$(ls | wc -l)
prompt: student@linuxcamp:~$ answer: echo "There are $count files" output: There are 3 files hint: Reuse the variable with a dollar sign inside double quotes: echo "There are $count files"
Two lines, one idea. The first line ran ls | wc -l inside $(...), so the counting happened right away and the number 3 was stored in count. Notice the assignment printed nothing on its own: storing a value is silent. The second line pulled that stored 3 back out with $count and wrapped it in a readable sentence. On a folder with a different number of files, the 3 changes, but the mechanism does not: capture once, reuse as often as you like.
You do not have to store the result. You can drop a substitution straight into another command as an argument. The machine's own name is a good example: hostname prints it, and you can inline that into a sentence without ever knowing the name in advance.
echo "This host is $(hostname)"
prompt: student@linuxcamp:~$ answer: echo "This host is $(hostname)" output: This host is linuxcamp hint: Same shape as before, with hostname inside the brackets: echo "This host is $(hostname)"
The name linuxcamp is this machine's. On your machine hostname prints whatever your computer is called, so that last word will read differently. The fixed part This host is is what you typed, and it never moves. This is the everyday use of a substitution: you know the shape of the sentence, and you let the command fill in the one live detail.
One gotcha bites nearly everyone once. When a substitution produces text with spaces in it, and you leave it unquoted, the shell splits that text on the spaces into separate words before your command sees it. That is called word splitting, and it quietly changes what your command receives.
The fix is simple and worth making a habit: wrap the substitution in double quotes, "$(command)", and its whole output arrives as one piece, spaces and all. Every example in this lesson already did this, and now you know why. Print the full date, which is several words, safely inside quotes:
echo "$(date)"
prompt: student@linuxcamp:~$ answer: echo "$(date)" output: Mon Jul 5 14:03:07 UTC 2026 hint: Wrap the whole substitution in double quotes: echo "$(date)"
That date line is the moment this was captured, so yours will show a different day and time. Two more honest limits to keep in mind. First, only what a command prints to the screen, its standard output, is captured; error messages travel a separate channel and do not land in the substitution. Second, if the inner command fails, it usually prints nothing, so the substitution comes back empty, and you get a blank where you expected a value. When a substitution mysteriously produces nothing, check that the inner command actually works on its own first.
Scaffolding off. No command is printed this time. You have every piece you need.
You want to greet the machine by name, exactly as you did before, but from memory. Print the sentence This host is followed by the machine's real name, filled in by a command, all in one line. Think about which command prints the name, and how you wrap it so its output drops into your sentence.
prompt: student@linuxcamp:~$ answer: echo "This host is $(hostname)" output: This host is linuxcamp hint: Recall the shape: echo, a quoted sentence, and the name-printing command wrapped in $(...). The command that prints the machine name is hostname.
That is the everyday move. echo printed your fixed words, and $(hostname) ran on its own and dropped the machine's real name into the gap. The name you saw is this machine's; yours will differ, but the command is identical everywhere. You recalled the whole shape from memory, the quotes, the dollar sign, the brackets, and that is exactly the recall the real machine will ask of you.
You earned this cheat sheet. Every row is a form you just ran:
The three rules under it all: the inner command runs first, only its standard output is captured, and you wrap it in double quotes to keep multi-word output together. When you need a value you do not know yet, that is the moment for $(...).
Reach for $(...) any time you would otherwise run a command, read its output, and type that output back in by hand. Dated backup names like backup-$(date +%F).tar, counts, the current directory, the logged-in user: let the command fill it in, and your line stays correct even as the value changes.
The practice terminal has shown you the whole story of command substitution. You dropped a command's output into a sentence. You captured a count into a variable and reused it. You inlined the machine's own name, and you learned to quote a substitution so multi-word output stays in one piece. Every one of those you typed yourself.
The Bash Environment module ends with one real Linux machine, the Bash Environment capstone mission, and that is where you use $(...) for real. A VM boots just for you, with its own live environment: real dates, a real hostname, real files to count. It hands you objectives that use exactly what you practiced across this module: variables, expansions, quoting, and the substitutions that tie them together. One difference from here: the mission shows no commands. You read the objective, you recall the command, you type it. That recall is what makes it stick.
Finish the other Bash Environment lessons, then go let a command write your command line for you.
Practice Command Substitution in a real Linux terminal at The Linux Camp. Progress is verified automatically as you type commands on the machine.