1. Overview
When we have complex shell scripts, we often need to use the output of other commands in our logic.
In this quick tutorial, we’ll see how to do this with command substitution.
2. Syntax
Let’s first take a look at the syntax. Due to historical reasons, we can use two types of syntax:
$(command)
`command`
The first form is recommended because it solves an inconsistent behavior. It is also much more readable.
We should keep in mind that command substitution spawns a sub-shell.
Let’s see a simple example:
$ echo "Current path is ["$(pwd)"]"
Current path is [/home/baeldung]
This also works with the old syntax:
$ echo "Current path is ["`pwd`"]"
Current path is [/home/baeldung]
In this example, the output of the pwd command replaces the actual command.
So what is the difference between the formats?
Let’s consider this example:
$ function different_syntax() {
echo "Backticks ["`echo \\baeldung`"]"
echo "Dollar ["$(echo \\baeldung)"]"
}
$ different_syntax
Backticks [baeldung]
Dollar [\baeldung]
The
Consider that we have a variable pointing to a directory that exists:
$ function different_syntax() {
dir="/home"
echo "Backticks ["`ls \$dir`"]"
echo "Dollar ["$(ls \$dir)"]"
}
$ different_syntax
Backticks [baeldung demo]
ls: cannot access '$dir': No such file or directory
Dollar []
In the first case, the
3. Quoting and Nesting
Now that we’ve seen the basic syntax, let’s see some advanced scenarios.
We can use nesting in a command substitution expression:
$ function nesting() {
current_folders=$(ls $(pwd))
echo "Current folders in $(pwd) ["$current_folders"]"
}
$ nesting
Current folders in /home [baeldung demo]
First, the current path replaces the pwd command. Then, we pass this to ls and substitute the whole expression with its output. Finally, we store the output in a variable.
When we use double quotes, Bash does not perform word splitting or filename expansion:
$ function quoting() {
for element in $(ls $(pwd))
do
echo "["$element"]"
done
}
$ quoting
[baeldung]
[demo]
In this case, we iterate over all the files in the current directory.
Now let’s see what happens if we use quotes in our loop:
$ function quoting() {
for element in "$(ls $(pwd))"
do
echo "["$element"]"
done
}
$ quoting
[baeldung demo]
Since word splitting did not occur, we iterate over a single element.
Let’s finish with a useful snippet:
$ ps -g $(ps -C firefox -o sid=)
PID TTY TIME CMD
1652 ? 00:02:48 gnome-shell
1815 ? 00:00:12 Xwayland
2207 ? 00:00:09 ibus-daemon
2214 ? 00:00:00 ibus-dconf
2215 ? 00:00:02 ibus-extension-
2217 ? 00:00:00 ibus-x11
2232 ? 00:00:02 ibus-engine-sim
2533 ? 00:09:36 firefox
2670 ? 00:00:32 WebExtensions
...
Let’s see what it does. First, we search a particular process using the ps command and print its session id.
We use the = after the output specifier to suppress the headers in the nested command.
We then use this output (the session id) to print all the processes in this particular session.
4. Conclusion
In this quick tutorial, we saw how to use command substitution.
First, we talked about the two types of basic syntax and discussed the differences between them.
After that, we saw how command-substitution nesting works.
Finally, we explained how quoting affects the results of command substitution.