Command substitution allows a command line to be comprised, in part, of the output of other commands.
For example, let’s say we want the symbol THIS_HOST
to hold the hostname of the system we’re running on. We can find the hostname with the hostname
command:
$ hostname awe
The Old Way
There are two straightforward ways of assigning the hostname to a symbol. The older, deprecated, way is to enclose the command in backticks:
$ THIS_HOST=`hostname` $ echo $THIS_HOST awe
That syntax is still in common use, but it has a number of disadvantages:
- It’s too easy to misinterpret what’s been written as single quotes. That’s not a mistake an experienced Linux administrator will make, but we all have to learn some time, and others may not appreciate the difference between a backtick and a single quote.
- Nesting substitutions is very challenging. Yes, with sufficient escaping it can be done – but there’s no need.
A Better Way
The preferred syntax these days is to wrap the command to be substituted in a $(...)
construction. Our host name example now becomes:
$ THIS_HOST=$(hostname)
That, I would suggest, is much easier to read, regardless of how experienced you are.
Nested Substitution
It’s also possible to nest substitutions easily. Let’s say we want to assign the time since a file was last modified, in seconds, to the symbol age
, and let’s use the symbol FILE
to hold the path of the file in question. We can find the last modified time in seconds since the Epoch like this:
$ FILE=/tmp/mytestfile $ touch $FILE $ stat -c %Y ${FILE} 1499673894
And we can find the current time since the Epoch, in seconds, with:
$ date +%s 1499673946
Subtracting the first from the second will give us the age of the file in seconds.
$ age=$(($(date +%s) - $(stat -c %Y ${FILE}))) $ echo $age 52
The two time-since-epoch are each wrapped in a $(...)
construction, so the above command becomes (the actual numbers will vary, of course):
$ age=$((1499673946 - 1499673894))
The bash shell will carry out calculations within a $((...))
construction, and hence yield the time since last modification in seconds. Yes, it is confusing: single parentheses for command substitution, and double parentheses for expression evaluation.
Backticks still work, but I’d suggest it’s worth using the later form in future.
Could this Linux Tip be improved?
Let us know in the comments below.