122

How to check what shell I am using in a terminal? What is the shell I am using in MacOS?

Michael Mrozek
  • 93,103
  • 40
  • 240
  • 233
user5837
  • 1,321

12 Answers12

114

Several ways, from most to least reliable (and most-to-least "heavy"):

  1. ps -p$$ -ocmd=. (On Solaris, this may need to be ps -p$$ -ofname= and on macOS and on BSD should be ps -p$$ -ocommand=.)
  2. Check for $BASH_VERSION, $ZSH_VERSION, and other shell-specific variables.
  3. Check $SHELL; this is a last resort, as it specifies your default shell and not necessarily the current shell.
tomglynch
  • 103
geekosaur
  • 32,047
  • 8
    Should you mention $0 too? – Mikel Mar 18 '11 at 02:41
  • I don't like $0 because it's more complicated: (1) it may be just the basename, (2) it may have '-' on the front to designate it as a login shell. – geekosaur Mar 18 '11 at 02:44
  • ps -p$$ -ocmd="" is prettier :-) – asoundmove Mar 18 '11 at 03:51
  • 1
    @geekosaur: maybe so, but $0 still seems more useful than $SHELL: wouldn't you agree? You could always pipe it through sed to remove the '-'. – iconoclast Aug 29 '12 at 21:49
  • 5
    On Mac, #1 is ps -p $$ -o comm="". Also, for those wondering, $$ is the shell process ID. – duozmo Oct 19 '13 at 18:00
  • 2
    If you're running tcsh, $tcsh and $version will be set. These are shell variables, not environment variables. If you're running a non-tcsh version of csh, I don't think there are any distinctive variables. And of course the syntax used to check variables differs between csh/tcsh on the one hand, and sh/ksh/bash/zsh on the other. – Keith Thompson Mar 18 '14 at 01:51
  • On HP-UX, ps -p$$ -ocommand= doesn't work either ("illegal option" for each of the letters after -o). The same with ps -p$$ -ofname. – Peter Mortensen Jul 31 '18 at 11:48
  • $BASH_VERSION is enough to check whether the currently running is bash. I'd use this to detect whether any shell other than bash is being used. – xdevs23 Dec 21 '19 at 21:56
  • #1 is definitely heavier - running a command - but how is it more reliable that variables like $ZSH_VERSION? – Denis Howe Apr 08 '21 at 16:11
  • I wouldn't put ps -p$$ -ocmd= to the top of "reliable" list. I just was getting errors in my script, and then turned out the command returned not bash, not zsh, but "bash test.sh". So no, you can't rely on this. – Hi-Angel Apr 21 '21 at 14:28
  • Yes, 3 not works well. I have set up a terminal profile to run bash on startup. In this case I use bash but $SHELL returns zsh. – Antonio Oct 09 '22 at 10:04
64

I've found that the following works in the four shells I have installed on my system (bash, dash, zsh, csh):

$ ps -p $$

The following works on zsh, bash, and dash, but not on csh:

$ echo $0
Steven D
  • 46,160
10

As the question asks for the shell used and does not talk about the potential arguments passed to it, here is a way that avoid showing them:

$ ps -o comm= -p $$
ksh93 
jlliagre
  • 61,204
8

A note about some lighter implementations (Android phones, busybox, etc.): ps doesn't always have support for the -p switch, but you can accomplish the search with a command like ps | grep "^$$ ". (This grep regex will uniquely identify the PID, so there will not be any false positives.)

palswim
  • 5,167
7

There are two really simple ways:

  • Using ps command:

    ps -o comm= $$
    

    or

    ps -h -o comm -p $$
    

    where:

    • -h or finishing all options with = for not showing any header.
    • -o comm for showing only the process basename (bash instead of /bin/bash).
    • -p <PID> list only process whith PID form list suplied.
  • Using the /proc process information pseudo-file system:

    cat /proc/$$/comm
    

    This option behaves exactly as the ps command above.

    or

    readlink /proc/$$/exe
    

    This /proc/PID/exe links to the file being executed, which in this case would point to /bin/bash, /bin/ksh, etc.

    For getting only the name of the shell you can just use

    basename $(readlink /proc/$$/exe)
    

    This is the only option that will always give the same result even if you are in an script, sourced code, or terminal, as links to the binary of the shell interpreter in use.

    Warning You must be aware that this will show the ultimate binary, so ksh may be linked to ksh93 or sh to bash.

The usage of /proc is really useful via the /proc/self, which links to the PID of the current command.

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
  • 2
    basename $(readlink /proc/$$/exe) is Korn/POSIX shell syntax. Won't work in csh/tcsh/rc/es/akanga/fish. $$ won't work in rc/es/akanga/fish. – Stéphane Chazelas Oct 09 '20 at 07:27
  • basename $(readlink /proc/$$/exe) is the only command here that could work for me in a docker image with no ps installed. – Flavin Apr 21 '21 at 13:15
  • macOS (which the user in the question is using) does not have a /proc filesystem. – Kusalananda Mar 19 '24 at 10:57
4

A mix of all the other answers, compatible with Mac (comm), Solaris (fname) and Linux (cmd):

ps -p$$ -o cmd="",comm="",fname="" 2>/dev/null | sed 's/^-//' | grep -oE '\w+' | head -n1
sebastien
  • 141
  • this gives me my current directory name; also, under csh and tcsh it gives me Ambiguous output redirect. – iconoclast Aug 07 '15 at 00:17
  • This is also what Anaconda uses (version 2022.05) in it's [env]/bin/activate script to detect shell type. A comment in that file explicitly links to this answer. – Neinstein Jun 10 '22 at 11:41
  • head takes the first match which is bin from /bin/foosh in most cases. tail -n1 would take the last, which is probably the desired shell – Sparr Nov 27 '23 at 19:49
3

If you have it saved in your environment variables you can use the following:

echo $SHELL

For accuracy in many different shells you should use

ps -p $$

Why does this work?

echo $$ # 998

What is that number?

It's the process id of the current shell.

$ expands to the same value as the current shell.

$$ process ID of the parent in a sub shell

If you only want then name of the shell you could use

ps -p $$ | awk '{if(NR>1)print}' | awk '$0=$NF' | tr -d -

In a nutshell we are taking the output of the process sub shell and piping it to some formatting tools awk, sed and tr all work for this, removing the first 3 columns, the first line of output, and then the - gives just the name of the shell. Consider putting that into a function for ease later.

  • That will most likely return the pathname of the shell executable of your login shell. It is not certain that the login shell is what you are currently running though. – Kusalananda Apr 10 '19 at 06:39
  • I have updated my answer to provide more value and understanding. – jasonleonhard Aug 05 '20 at 18:16
2

I set $MYSHELL for future tests in my shell-agnostic ~/.aliases:

unset MYSHELL
if [ -n "$ZSH_VERSION" ] && type zstyle >/dev/null 2>&1; then           # zsh
  MYSHELL=`command -v zsh`
elif [ -x "$BASH_VERSION" ] && type caller >/dev/null 2>&1; then        # bash
  MYSHELL=`command -v bash`
elif [ -x "$shell" ] && which setenv |grep -l builtin >/dev/null; then  # tcsh
  echo "DANGER: this script is likely not compatible with C shells!"
  sleep 5
  setenv MYSHELL "$shell"
fi

verify

if [ ! -x "$MYSHELL" ]; then MYSHELL=command -v &quot;$(ps $$ |awk 'NR == 2 { print $NF }')&quot; [ -x "$MYSHELL" ] || MYSHELL="${SHELL:-/bin/sh}" # default if verify fails fi

The tcsh section is likely unwise to roll into a POSIX-style script since it's so radically different (thus the warning and five second pause). (For one, csh-style shells can't do 2>/dev/null or >&2, as noted in the famous Csh Programming Considered Harmful rant.)

Adam Katz
  • 3,965
1

The pid of the running shell is given by the var $$ (in most shells).

whichsh="`ps -o pid,args| awk '$1=='"$$"'{print $2}'`"
echo "$whichsh"

Using backticks to make jsh (Heirlomm shell) work.

In many shells the direct test of ps -o args= -p $$ works, but busybox ash fails on that (solved).

The check that $1 must be equal to $$ removes most false positives.

The last ;: are used to keep the shell running for ksh and zsh.

Tests on more systems will help, please make a comment if it doesn't work for you.

Does not work in csh type of shells.

0

Good question me too on my Mac had the same doubt.

Another method, dirty but "it works", it really simple; you should launch a command that does not exist. The the shell reply the classical "command not found", but first shows its name. :-)

~$ piripicchio
-bash: piripicchio: command not found

and

~ % piripicchio
zsh: command not found: piripicchio`


Also, you could note that zsh prompt is "%" and bash is "$" but my root on bash has "%" too.

Antonio
  • 153
0

For anyone wanting to check the current shell in a shell script using a shebang (because the other answers will give the script name in this case):

ps -p$PPID

or to get only the name:

ps -p$PPID | grep -v "PID" | awk '{print $4}'

Explanation:

  • $PPID is the process id of the parent to the current process (the shell executing the current script)
  • ps -p gets information on the given process
  • grep -v "PID" removes the header line
  • awk '{print $4}' gets the fourth column (which is the command name)
MC68020
  • 7,981
-1

echo ${0//-/}

This one returns bash or zsh even if it's a login shell (ie. starting with -).

Dorian B.
  • 139