Command substitution

While not strictly redirection in the Linux sense, command substitution in our eyes is a form of functional redirection: you use the output of a command as an argument to another command. If we needed to use output as input for the next command, we'd use a pipe (as we'll see in a few pages), but sometimes we just need that output at a very specific location in our command.

This is where command substitution is used. We've already seen command substitution in some of our scripts: cd $(dirname $0). Simply put, this does something like cd to the result of dirname $0.

dirname $0 gives back the directory where the script is located (since $0 is the fully-qualified path of the script), so when we use this with scripts, we'll make sure all operations are always carried out relative to the directory where the script is located.

If we did not have command substitution, we'd need to store the output somewhere before we could use it again:

dirname $0 > directory-file
cd < directory-file
rm directory-file

While this sometimes works, there are some pitfalls here:

  • You need to write a file somewhere where you have write permissions
  • You need to clean up the file after the cd
  • You need to make sure the file does not conflict with other scripts

To cut a long story short, this is a far from ideal solution, and best avoided. And since Bash supplies command substitution, there is no real drawback to using it. As we've seen, the command substitution in cd $(dirname $0) handles this for us, without the need for us to track files or variables or any other complicated constructions.

Command substitution is actually used quite a lot in Bash scripting. Take a look at the following example, in which we use command substitution to instantiate and populate a variable:

reader@ubuntu:~/scripts/chapter_12$ vim simple-password-generator.sh 
reader@ubuntu:~/scripts/chapter_12$ cat simple-password-generator.sh
#!/bin/bash

#####################################
# Author: Sebastiaan Tammer
# Version: v1.0.0
# Date: 2018-11-10
# Description: Use command substitution with a variable.
# Usage: ./simple-password-generator.sh
#####################################

# Write a random string to a variable using command substitution.
random_password=$(tr -dc 'a-zA-Z0-9' < /dev/urandom | head -c 20)

echo "Your random password is: ${random_password}"

reader@ubuntu:~/scripts/chapter_12$ bash simple-password-generator.sh
Your random password is: T3noJ3Udf8a2eQbqPiad
reader@ubuntu:~/scripts/chapter_12$ bash simple-password-generator.sh
Your random password is: wu3zpsrusT5zyvbTxJSn

For this example, we reused the logic in our earlier password-generator.sh script. This time, we do not give the user the option to supply a length; we keep it simple and assume a length of 20 (which is, at least in 2018, a pretty good length for a password).

We use command substitution to write the result (the random password) to a variable, which we then echo to the user.

We actually could have done this in a single line:

reader@ubuntu:~/scripts/chapter_12$ echo "Your random password is: $(tr -dc 'a-zA-Z0-9' < /dev/urandom | head -c 20)"
Your random password is: REzCOa11pA2846fvxsa

However, as we have discussed many times by now, readability counts (still!). We feel that first writing to a variable with a descriptive name, before we actually use it, increases the readability of the script.

Furthermore, if we wanted to use the same random value more than once, we need a variable anyway. So in this case, the extra verbosity in our script helps us and is desirable.

The predecessor to $(..) was the use of backticks, which is the ` character (found next to the 1 on English-International keyboards). $(cd dirname $0) was previously written as `cd dirname $0`. While this mostly does the same as the newer (and better) $(..) syntax, there are two things that were often an issue with backticks: word splitting and newlines. These are both issues that are caused by whitespace. It is much easier to use the new syntaxes and not have to worry about things like this!
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.98.34