40

If I open a terminal like xterm I will have a shell. Then if I use ssh or zsh I will have another "level" of shell. Is there a way to know how many times I have to Ctrl+D or type exit to exit all of them? My real intention is to exit everything except the "root" shell.

It will also be nice to know what effect(s) terminal multiplexers (like screen) have on the solution.

PS: Please feel free to change the title, I don't know if those are the correct terms.

phunehehe
  • 20,240

5 Answers5

46

You have in fact hit upon the correct term¹. There is an environment variable SHLVL which all major interactive shells (bash, tcsh, zsh) increment by 1 when they start. So if you start a shell inside a shell, SHLVL increases by 1.

This doesn't directly answer your concern, however, because SHLVL carries over things like terminal emulators. For example, in my typical configuration, $SHLVL is 2 in an xterm, because level 1 corresponds to the shell that runs my X session (~/.xinitrc or ~/.xsession).

What I do is to display $SHLVL in my prompt, but only if the parent process of the shell is another shell (with heuristics like “if its name ends in sh plus optional punctuation and digits, it's a shell”). That way, I have an obvious visual indication in the uncommon case of a shell running under another shell.

Maybe you would prefer to detect shells that are running directly under a terminal emulator. You can do this fairly accurately: these are the shells whose parent process has a different controlling terminal, so that ps -o tty= -p$$ and ps -o tty= -p$PPID produce different output. You might manually reset SHLVL to 1 in these shells, or set your own TERMSHLVL to 1 in these shells (and incremented otherwise).

¹ Although one wouldn't think it looking at the manual pages: none of the three shells that support it include the word “level” in their documentation of SHLVL.

  • Thanks for confirming the term. I'm still on a mac and surprised to find those 2 commands give the same result, regardless of my shell level. – phunehehe Oct 17 '10 at 12:08
  • @phunehehe: what 2 commands? If you mean ps -o tty= -p$pid, this shows the process's controlling terminal, which identifies the terminal emulator (xterm, screen, sshd, …) that the process is running in. It will not change if you start a shell from another shell, but will change if you start a new terminal emulator. If the terminal emulator is a native Mac application, there may be a Mac-specific subtlety that I'm unaware of. – Gilles 'SO- stop being evil' Oct 17 '10 at 12:14
  • ps -o tty= -p$$ and ps -o tty= -p$PPID, because you said they should produce different output. Or did I misunderstand something? – phunehehe Oct 17 '10 at 12:44
  • @phunehehe: They give different output when if the parent process of the shell is a terminal emulator, because the terminal emulator doesn't have its emulated terminal as a controlling terminal. If you find otherwise, please post the output of ps -p $$ -p $PPID (again, I have no OSX experience, so maybe there's something unusual going on on OSX). – Gilles 'SO- stop being evil' Oct 17 '10 at 12:53
  • @Gilles: that was indeed something unusual with OSX. I tested on Gentoo and everything was correct as you said. On OSX, ps -p $$ -p $PPID gives (sorry I don't know how to format comments) PID TTY TIME CMD 209 ttys000 0:00.01 login -pf phunehehe 210 ttys000 0:00.12 -bash – phunehehe Oct 17 '10 at 14:14
  • Not that this is a surprise, but SHLVL didn't work that way on SunOS 4.1.3, FYI. :D – Kevin Cantu Oct 19 '10 at 20:37
  • @Kevin: Oops. Thanks, I just checked, and ksh in fact doesn't document SHLVL because it doesn't actually have that feature. (I thought that was where it came from, but clearly not.) – Gilles 'SO- stop being evil' Oct 19 '10 at 20:48
7

One (admittedly not perfect) way is to add the result of ps --no-headers -o comm $PPID to your shell prompt. This will tell you the name of the process that spawned your shell. If you're inside a nested zsh, it will say "zsh". If you're inside a top-level zsh, it will read "xterm" or "screen" or whatever your shell is running in.

To tell whether you're inside an ssh or su session, you can simply look at the hostname and username part of your prompt.

When you're running nested screens (which I don't imagine is a common situation), there's no way I can think of to tell whether you're in the top-level shell of a nested screen, or the top-level shell of the top-level screen. You could configure screen to always display a status line, which would cause multiple status lines to be displayed, if you're in nested screens.

sepp2k
  • 5,597
  • Aaah... snap.. beat me to it. :) +1 – Stefan Oct 17 '10 at 11:24
  • Currently I'm on a mac and the command gave me ps: illegal option -- -, any idea why? I'll test it again in Linux soon :) – phunehehe Oct 17 '10 at 12:00
  • 3
    @phunehehe: --option-name is mostly a GNU-specific features, so is mostly not available in standard system utilities outside Linux. But you can get the effect of ps --no-headers portably by adding = after the column name. Also the comm column is not POSIX, but the cmd column (which includes the arguments of the command) is. Also -p is necessary before the PID in POSIX syntax. Hence ps -o cmd= -p $PPID is portable and gives similar information. – Gilles 'SO- stop being evil' Oct 17 '10 at 12:17
  • confirmed, works on Gentoo – phunehehe Oct 17 '10 at 14:09
  • 2
    @phunehehe: sorry, I made a mistake in the comment above. In fact the comm column is specified by POSIX and documented on Mac OS X, whereas the cmd column exists on Linux but is not standard. – Gilles 'SO- stop being evil' Oct 17 '10 at 18:29
  • This, however, is supported by OS X: ps -o comm= $PPID – interestinglythere Oct 19 '15 at 11:40
1

You can use the environment variable SHLVL:

echo "$SHLVL"
A.B.
  • 3,442
Alex
  • 21
1

Not very elegant, but you could use tree view in htop to see parent-child relationship of your shell to other running proccesses.

$ htop # then press 't' and scroll around or 'Ctrl-W' to find your shell proccess

And use that to deduce the ammount of shells you will need to exit, before ariving at the "root" shell

Stefan
  • 25,300
0

I find that

$ pstree -u | grep ${USER}

can be quite helpful for seeing where I "fit in" on a system. I prefer it over pstree -u ${USER}.

Occasionally it will remind me that I left a nohup job running, or similar.

(Also, I use alias grep='grep --color=auto'.)

J_H
  • 866