We're an ISO27001:2013 Certified Supplier


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

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

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} 

And we can find the current time since the Epoch, in seconds, with:

$ date +%s 

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

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.