简体   繁体   中英

Bash nested subshell argument expansion

Why is the $bar being printed here as a literal, even thought the outer subshell should expand it's parameters according to bash command line processing rules?

$ foo='$bar' bar=expanded
$ echo $(echo $(echo $foo))
$bar

The inner subshell prints $bar , but why doesn't the outer subshell expand it? Does the bash implicitly pass it as a literal and if so, why and how? According to my knowledge, the parameter expansions happens after each fork of the subshell, inside the new process. In the case of nested subshells, the command substitution is done from inside out, inner subshell printing out the literal, raw text representation of the outer shell command line before the fork happens and the command line (string of characters) is being split, expanded and processed by the new shell. Now the question is, why the text $bar is not expanded in the outer subshell, even thought it actually doesn't contain quotes? What causes it to be implicitly quoted here?

Here is example of the same logic and expected output without nested shells

$ foo='$bar' bar=expanded
$ echo $foo
$bar
$ echo $bar
expanded

Also, by adding eval I get the result which I would expect in the first example, but I don't undertand why it's necessary and how it wokrs.

$ echo $(eval echo $(echo $foo))
expanded

The Bash manual explains the ordering shell expansions: (reformatted for clarity)

The order of expansions is:

  • brace expansion;

  • tilde expansion, parameter and variable expansion, arithmetic expansion, and command substitution (done in a left-to-right fashion);

  • word splitting;

  • and filename expansion.

On systems that can support it, there is an additional expansion available: process substitution. This is performed at the same time as tilde, parameter, variable, and arithmetic expansion and command substitution.

After these expansions are performed, quote characters present in the original word are removed unless they have been quoted themselves (quote removal).

This essentially echoes the Posix shell specification with the addition of some bash-specific expansions.

Note that the second group of expansions, which includes command substitution ( $(...) ) is only performed once, left-to-right. They are not performed repetitively, so the result of a command substitution is not subject to parameter expansion. Unless quoted, it is subject to word-splitting, filename expansion, and quote removal.

The commands evaluated in subshells are, indeed, evaluated inside out, but at each level the inner command substitution is only subject to word-splitting, filename expansion and quote removal (none of which apply in thus example).

So the only parameter expansion done is the replacement of $foo with its value.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM