Difference between linux variables $BASH_SUBSHELL

2019-04-06 15:20发布

I am confused between the two.

While the $BASH_SUBSHELL internal variable indicates the nesting level of a subshell, the $SHLVL variable shows no change within a subshell.

What does it exactly mean? If i open a shell within another shell, the value of $SHLVL increments. Isn't that a subshell?

标签: linux bash shell
2条回答
何必那么认真
2楼-- · 2019-04-06 15:41

$SHLVL:
Shell level, how deeply Bash is nested. If, at the command-line, $SHLVL is 1, then in a script it will increment to 2. This variable is not affected by subshells.

$BASH_SUBSHELL:
A variable indicating the subshell level.

Here is how they will have different values:

# In the login bash shell
echo $BASH_SUBSHELL:$SHLVL
0:1

# 1st nested child
bash
echo $BASH_SUBSHELL:$SHLVL
0:2

# 2nd nested child
bash
echo $BASH_SUBSHELL:$SHLVL
0:3

# back to 1st nested child
exit
echo $BASH_SUBSHELL:$SHLVL
0:2

# back to parent shell
exit
echo $BASH_SUBSHELL:$SHLVL
0:1

# first level sub-shell    
(echo $BASH_SUBSHELL:$SHLVL)
1:1

# 2nd level sub-shell
( (echo $BASH_SUBSHELL:$SHLVL) )
2:1

# 3rd level sub-shell
( ( (echo $BASH_SUBSHELL:$SHLVL) ) )
3:1
查看更多
SAY GOODBYE
3楼-- · 2019-04-06 15:51

No, manually running a new shell (via /bin/sh or /bin/bash etc.) is not a subshell in this context.

A subshell is when the shell spawns a new shell instance on its own to handle some work.

Using Command Substitution (i.e. $(command)) is a subshell (as is the older backticks invocation).

Using a pipeline (i.e. echo '5.1+5.3' | bc -l) creates subshells for each component of the pipeline.

Using Process Substitution (i.e. <(command)) creates a subshell.

Grouping commands (i.e. (declare a=5; echo $a)) creates a subshell.

Running commands in the background (i.e. sleep 1 &) creates a subshell.

There may be other things as well but those are the common cases.

Testing this is easy:

$ printf "Outside: $BASH_SUBSHELL , $SHLVL\nInside: $(echo $BASH_SUBSHELL , $SHLVL)\n"
Outside: 0 , 1
Inside: 1 , 1
$ (printf "Outside: $BASH_SUBSHELL , $SHLVL\nInside: $(echo $BASH_SUBSHELL , $SHLVL)\n")
Outside: 1 , 1
Inside: 2 , 1
$ bash -c 'printf "Outside: $BASH_SUBSHELL , $SHLVL\nInside: $(echo $BASH_SUBSHELL , $SHLVL)\n"'
Outside: 0 , 2
Inside: 1 , 2
$ bash -c '(printf "Outside: $BASH_SUBSHELL , $SHLVL\nInside: $(echo $BASH_SUBSHELL , $SHLVL)\n")'
Outside: 1 , 2
Inside: 2 , 2

The source of your quote (the generally poor, and often better avoided, ABS) even demonstrates this a little bit (and in a rather unclear manner, just another instance of the general lack of rigor and quality in that "Advanced" guide):

echo " \$BASH_SUBSHELL outside subshell       = $BASH_SUBSHELL"           # 0
  ( echo " \$BASH_SUBSHELL inside subshell        = $BASH_SUBSHELL" )     # 1
  ( ( echo " \$BASH_SUBSHELL inside nested subshell = $BASH_SUBSHELL" ) ) # 2
# ^ ^                           *** nested ***                        ^ ^

echo

echo " \$SHLVL outside subshell = $SHLVL"       # 3
( echo " \$SHLVL inside subshell  = $SHLVL" )   # 3 (No change!)
查看更多
登录 后发表回答