How do I know if I have a nested shell?

When using the * nix shell (usually bash), I often create a sub-shell with which I can take care of a small task (usually in a different directory) and then exit it to resume the parent shell session.

From time to time I will lose information about whether I launch a nested shell or into a top-level shell, and I accidentally create an additional sub-shell or exit the top level by mistake.

Is there an easy way to determine if I'm running in a nested shell? Or am I turning to my problem (by spawning sub-shells) completely wrong?

+60
linux unix bash shell
Dec 22 '10 at 16:39
source share
9 answers

The $SHLVL monitors the nesting level of the shell:

 $ echo $SHLVL 1 $ bash $ echo $SHLVL 2 $ exit $ echo $SHLVL 1 



As an alternative to spawning sub-shells, you can click and call directories from the stack and remain in the same shell:

 [root@localhost /old/dir]# pushd /new/dir /new/dir /old/dir [root@localhost /new/dir]# popd /old/dir [root@localhost /old/dir]# 
+69
Dec 22 '10 at 16:48
source share

Here is a simplified version of part of my invitation:

 PS1='$(((SHLVL>1))&&echo $SHLVL)\$ ' 

If I’m not in a nested shell, this doesn’t add anything superfluous, but shows depth if I am at any level of nesting.

+23
Dec 22 '10 at 19:27
source share

Look at $0 : if it starts with a minus - , you are in the login shell.

+11
Dec 22 2018-10-22
source share

pstree -s $$ very useful to see your depth.

+8
Jan 31 '14 at 7:10
source share

The $SHLVL environment $SHLVL contains the "depth" of the shell.

 echo $SHLVL 

Shell depth can also be determined using pstree (version 23 and above):

 pstree -s $$ | grep sh- -o | wc -l 

I found the second way to be more reliable than the first, whose value was reset when using sudo or became unreliable with env -i .

None of them can correctly deal with su .




Information may be available at your invitation:

 PS1='\u@\h/${SHLVL} \w \$ ' PS1='\u@\h/$(pstree -s $$ | grep sh- -o | tail +2 | wc -l) \w \$ ' 

| tail +2 | tail +2 should remove one line from grep output. Since we use the pipeline inside the $(...) substitution, the shell needs to call a sub-shell, so pstree reports this, and grep detects another level of sh- .




In debian-based distributions, pstree is part of the psmisc package. It may not be installed by default for distributions without a desktop.

+1
Nov 02 '17 at 4:49 on
source share

ptree $$ will also show you how many levels you

0
Dec 22 '10 at 19:32
source share

I get root login .... bash ... so for me I need the 4th bash element, no grep, etc. pstree -p $$ | awk '{if ($ 4 ~ "bash") {print $ 0}}' | wc -l works better. I need -p to get pid, not pstree based on strings. Mac OSx 10.11.6 I could just print 4 dollars, but it’s useful to see whole lines in debugs

0
Dec 30 '17 at 14:36
source share

As @ John Kugelman says echo $SHLVL will tell you the depth of the bash shell.
And, as @Dennis Williamson shows, you can edit your invitation via the PS1 variable to print this value.

I prefer it to always print the shell depth value, so here's what I did: edit the file "~ / .bashrc":

 gedit ~/.bashrc 

and add the following line to the end:

 export PS1='\$SHLVL'":$SHLVL\n$PS1" 

Now you will always see a listing of your current bash level just above your prompt. Example: here you can see that I am at bash level (depth) 2, as indicated by $SHLVL:2 :

$ SHLVL: 2
7510-gabriels ~ $

Now follow the prompt when I go down to some bash levels with the bash command and then return via exit . Here you see my commands and a hint (answer), starting from level 2 and dropping to 5, then returning to level 2:

 $SHLVL:2 7510-gabriels ~ $ bash $SHLVL:3 7510-gabriels ~ $ bash $SHLVL:4 7510-gabriels ~ $ bash $SHLVL:5 7510-gabriels ~ $ exit exit $SHLVL:4 7510-gabriels ~ $ exit exit $SHLVL:3 7510-gabriels ~ $ exit exit $SHLVL:2 7510-gabriels ~ $ 

Bonus: show your current git branch , which you are also in!

Your invitation will also display your git branch that you are working on ; instead, use the following in the ~ / .bashrc file:

 git_show_branch() { __gsb_BRANCH=$(git symbolic-ref -q --short HEAD 2>/dev/null) if [ -n "$__gsb_BRANCH" ]; then echo "$__gsb_BRANCH" fi } export PS1="\e[7m\$(git_show_branch)\e[m\n\h \w $ " export PS1='\$SHLVL'":$SHLVL $PS1" 

Source: I have no idea where git_show_branch() came from, but I got it from Jason McMullan on April 5, 2018. Then I added the $SHLVL shown above only last week.

Output Example:

$ SHLVL: 2 master
7510-gabriels ~ / GS / dev / temp $

And here is a screenshot showing it in all its glory. Pay attention to the name of the git, master branch, highlighted in white!

enter image description here

0
Aug 26 '19 at 23:12
source share

If you use the following code inside a subcommand, you will get 2:

 ps | fgrep bash | wc -l 

Otherwise, it will give 1.

EDIT Okay, this is not such a reliable approach as mentioned in the comments :)
Another thing:

 ps -ef | awk '{print $2, " ", $8;}' | fgrep $PPID 

will give 'bash' if you are in a sub-shell.

-one
Dec 22 2018-10-22
source share



All Articles