Bash – How to *reliably* and *simply* get the current shell interpreter name

bashshellzsh

I'm looking for a simple and reliable way to get the name of the current shell from inside a script or a sourced file (not from the command line). I would have expected to just do $(basename "$SHELL") but if my login shell is zsh and I have the following code in some_script.sh

this_shell=$( basename "$SHELL" )
echo "The Shell is $this_shell"
echo "The Shell is $0"

and I run it with bash some_script.sh, it still lists zsh instead of bash even though the interpreter used is /bin/bash. I'm not sure why shell designers chose to show the default shell instead of the current shell, but that seems to be what we're stuck with.

There are some other slightly similar questions (here and here), but their answers fall short in many ways.

  1. They often assume the user is trying to figure out what interactive shell they're currently using, but that's crazy. I know what shell I'm typing commands into–I need code that could be run anywhere to be able to determine what shell it is using.
  2. They often give several different things to try–again as though you're on the command line and can just fiddle around until you learn you're using bash–but I need one single thing that is reliable in all contexts.
  3. They often give things that are utterly useless from scripts, like echo $0. That fails as shown in the script above. (Yes it works in an interactive shell command line, but why would you ever not know what shell you're using?)
  4. They sometimes give commands that (in my limited tests) include the correct information, like ps -p $$, but lack cross-platform, cross-shell compatible sed/awk commands to pipe it through to get just the shell name and ignore the other information that comes along for the ride.
  5. They include things that will only work on a couple of shells, like $BASH_VERSION and $ZSH_VERSION. I want to support as many shells as possible, such as fish, csh, tcsh.

How do I reliably and accurately detect any current shell? I'm looking for something that will work across platforms, in scripts, and for as many shells as possible and reasonable1.

UPDATE:
When I posted this question I expected that there was some facility built into the shells to give us this info, which appears to not be the case. Since it appears inevitable now to rely on something outside of the shells, I should make more explicit that I'm asking for a cross platform solution (which, though implied by my objections to other answers above, might be easy to miss if you don't read the question carefully).

Update 2
If anyone still believes this is a duplicate of the Linux-only question because Stéphane’s answer is not Linux-only, here are the differences between what I'm asking for and what he has provided. (Note that what he has written is ingenious, and I'm not knocking it, but it doesn't solve my problem.)

  1. I'm looking for something simple and reliable, that
  2. can be added to any script or function definition (that would be sourced by a .zshrc or .bash_profile or whatever) to branch.
  3. You cannot use his script as an outside utility that passes the interpreter name to the calling script/function, since it will always be interpreted by the default interpreter and return that. This makes it either difficult or impossible to use for my purposes. If it is possible, it is still very very difficult, and the solution to making it work is not given in the answer. Therefore he did not answer my question, therefore it is not a duplicate.

If you want to see something that will work, take a look at ShellDetective on GitHub. That may make it easier to see the differences between what is already present on SE, and what this question is looking for (and was in fact written in order to satisfy the needs of this question, which were unmet anywhere else).


(P.S. if you can't believe there's a use case for this, imagine functions that get sourced into .zshrc, .bash_profile, or .profile depending on what server is being used and what shells it has available. They're sourced so they have no shebang line. They are most useful if they can work in any shell, but sometimes they have to know which shell they're in to know how to behave.)


1 I'm not concerned with "shells" that are not shells in any traditional sense of the word. I'm not concerned with some shell that some guy wrote for himself. I'm only concerned with real shells that actually occur in the wild, and which someone might conceivably have to use when logging into some server on which they cannot just install whatever shells they want.

Best Answer

I've had great results with this combination:

ps -p $$ | awk '$1 != "PID" {print $(NF)}'

On Tru64 (OSF/1), the output has parentheses around the shell. Tack on tr -d '()' to remove them.

ps -p $$ | awk '$1 != "PID" {print $(NF)}' | tr -d '()'  

Appears to works on all shells, on Solaris 10 and RHEL 5.7 / 6.4. Didn't test other distros such as Debian, Ubuntu, or Mint, but I would think they should all work the same; I also have no idea if FreeBSD would work.

enter image description here

Related Question