Reputation: 21643
When using a *nix shell (usually bash), I often spawn a sub-shell with which I can take care of a small task (usually in another directory), then exit out of to resume the session of the parent shell.
Once in a while, I'll lose track of whether I'm running a nested shell, or in my top-level shell, and I'll accidentally spawn an additional sub-shell or exit out of the top-level shell by mistake.
Is there a simple way to determine whether I'm running in a nested shell? Or am I going about my problem (by spawning sub-shells) in a completely wrong way?
Upvotes: 71
Views: 15844
Reputation: 52449
As @John Kugelman says, echo $SHLVL
will tell you the bash shell depth.
And as @Dennis Williamson shows, you can edit your prompt via the PS1
variable to get it to print this value.
I prefer that it always prints the shell depth value, so here's what I've done: edit your ~/.bashrc
file:
gedit ~/.bashrc
and add the following line to the end:
export PS1='\$SHLVL'":$SHLVL\n$PS1"
Now you will always see a printout of your current bash level just above your prompt. Ex: here you can see I am at a bash level (depth) of 2, as indicated by the $SHLVL:2
:
$SHLVL:2 7510-gabriels ~ $
Now, watch the prompt as I go down into some bash levels via the bash
command, then come back up via exit
. Here you see my commands and prompt (response), starting at level 2 and going down to 5, then coming back up 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 ~ $
git branch
you are on too!Make your prompt also show you your git branch you are working on by using the following in your "~/.bashrc" file instead:
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()
originally comes from, but I got it from Jason McMullan on 5 Apr. 2018. I then added the $SHLVL
part shown above just last week.
Sample output:
$SHLVL:2 master 7510-gabriels ~/GS/dev/temp $
And here's a screenshot showing it in all its glory. Notice the git branch name, master
, highlighted in white!
PS1
promptI've improved my PS1
prompt again and put it in my eRCaGuy_dotfiles repo. It is inside my ~/.bash_aliases
file, which is sourced by my ~/.bashrc
file. Search my ~/.bash_aliases
file for both my PS1
entries and the gs_git_show_branch_and_hash
function used by them.
Here's a sample output of the new terminal prompt. Notice how it shows the shell level as 1
, and it shows the branch name of the currently-checked-out branch (master
in this case), as well as its short git hash (bac27c7
in this case), whenever I'm inside a local git repo!:
This is really helpful to help me ensure I'm always performing my git
operations on the correct branch, and to automatically see whenever I cd
into a Git repository.
Upvotes: 3
Reputation: 359845
Here is a simplified version of part of my prompt:
PS1='$(((SHLVL>1))&&echo $SHLVL)\$ '
If I'm not in a nested shell, it doesn't add anything extra, but it shows the depth if I'm in any level of nesting.
Upvotes: 24
Reputation: 2279
The environment variable $SHLVL
contains the shell "depth".
echo $SHLVL
The shell depth can also be determined using pstree
(version 23 and above):
pstree -s $$ | grep sh- -o | wc -l
I've found the second way to be more robust than the first whose value was reset when using sudo
or became unreliable with env -i
.
None of them can correctly deal with su
.
The information can be made available in your prompt:
PS1='\u@\h/${SHLVL} \w \$ '
PS1='\u@\h/$(pstree -s $$ | grep sh- -o | tail +2 | wc -l) \w \$ '
The | tail +2
is there to remove one line from the grep
output. Since we are using a pipeline inside a "$(...)
" command substitution, the shell needs to invoke a sub-shell, so pstree report it and grep detects one more sh-
level.
In debian-based distributions, pstree
is part of the package psmisc
. It might not be installed by default on non-desktop distributions.
Upvotes: 4
Reputation: 11996
If you running inside sub-shell following code will yield 2:
ps | fgrep bash | wc -l
Otherwise, it will yield 1.
EDIT Ok, it's not so robust approach as was pointed out in comments :)
Another thing to try is
ps -ef | awk '{print $2, " ", $8;}' | fgrep $PPID
will yield 'bash' if you in sub-shell.
Upvotes: -1
Reputation: 361547
The $SHLVL
variable tracks your shell nesting level:
$ echo $SHLVL
1
$ bash
$ echo $SHLVL
2
$ exit
$ echo $SHLVL
1
As an alternative to spawning sub-shells you could push and pop directories from the stack and stay 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]#
Upvotes: 92
Reputation: 78105
Look at $0
: if it starts with a minus -
, you're in the login shell.
Upvotes: 13