I'am working on Bash shell. When I enter commands in the following way

cmd1 $(cmd2) $(cmd3)

the order of executing the commands is: cmd2 -> cmd3 -> cmd1

When I look at the shell operation order of the Bash shell, I cannot fully grasp this situation.

Can you specify exactly how the Bash shell handles "command substitution"? For example, does tokenization return recursively on every command substitution?

  • How do you know the order? – choroba Mar 4 at 15:12
  • @choroba We can follow it in many different ways. For example, give the shell the set -x command, then you can use the command sleep 3 $(sleep 5) $(sleep 7) . Thanks to the working time of the sleep command, we can follow the commands numbers like 3 5 7. Similarly, with a tool such as htop, it is possible to make this tracking order instantly. – testter Mar 4 at 15:47
  • What do you mean by "does tokenization return recursively on every command substitution"? It may be an interesting point: apparently, Bash parses tokens when the expansion is performed; other shells may behave differently. On the other hand, tokenization does not happen on the result of expansions. – fra-san Mar 4 at 16:17

The reason is that command substitution, just as any other shell expansion, is designed to provide a dynamic means of generating command-line parameters for executing a command. So in order to run cmd1 with the output of cmd2 and cmd3 as arguments, these two have to be run first.

The exact order of shell expansions can be found e.g. in the Bash manual. Command substitution is ranked second after brace expansion, and at the same rank as tilde expansion, parameter (i.e. variable) expansion and arithmetic expansion. Those expansions that have equal rank are evaluated "in a left-to-right fashion", i.e. in the order they appear on the command line.

This would mandate that in case of nested substitutions, e.g.

cmd1 $(cmd2 $(cmd3)) $(cmd4)

the order would be cmd3 -> cmd2 -> cmd4 -> cmd1 as the first expansion would be that of $(cmd2 $(cmd3)) which itself needs expansion of $(cmd3), and then expansion of $(cmd4), before the results are passed to the call of cmd1.

  • I am confused about the expansion order. You indicated that the command substitution is ranked 4th after brace expansion, but the expansions "tilde" "parameter" "brace" all seem to have the same priority. I'm quoting: This is performed at the same time as tilde, parameter, variable, and arithmetic expansion and command substitution. gnu.org/software/bash/manual/html_node/Shell-Expansions.html unix.stackexchange.com/a/270324/364572 – testter Mar 5 at 14:54
  • 1
    @testter You are right, you actually pointed me to a misconception on my behalf there. I did some research and testing, and corrected the post accordingly. – AdminBee Mar 5 at 15:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.