26

How can I tell what type my shell is? ie, whether it's traditional sh, bash, ksh, csh, zsh etc.

Note that checking $SHELL or $0 won't work because $SHELL isn't set by all shells, so if you start in one shell and then start a different one you may still have the old $SHELL.

$0 only tells you where the shell binary is, but doesn't tell you whether /bin/sh is a real Bourne shell or bash.

I presume that the answer will be "try some features and see what breaks", so if anyone can point me at a script that does that, that'd be great.

Magpie
  • 607
  • 2
  • 7
  • 26
DrHyde
  • 1,546
  • 1
  • 14
  • 14
  • possible duplicate of [How to determine the current shell i'm working on ?](http://stackoverflow.com/questions/3327013/how-to-determine-the-current-shell-im-working-on) – Dennis Williamson Mar 02 '11 at 11:43
  • Thanks, that other post has some useful lists of env vars to check. – DrHyde Mar 03 '11 at 10:59
  • See also http://unix.stackexchange.com/questions/71121/determine-shell-in-script-during-runtime – clacke Apr 19 '13 at 10:32

7 Answers7

24

This is what I use in my .profile:

# .profile is sourced at login by sh and ksh. The zsh sources .zshrc and
# bash sources .bashrc. To get the same behaviour from zsh and bash as well
# I suggest "cd; ln -s .profile .zshrc; ln -s .profile .bashrc".
# Determine what (Bourne compatible) shell we are running under. Put the result
# in $PROFILE_SHELL (not $SHELL) so further code can depend on the shell type.

if test -n "$ZSH_VERSION"; then
  PROFILE_SHELL=zsh
elif test -n "$BASH_VERSION"; then
  PROFILE_SHELL=bash
elif test -n "$KSH_VERSION"; then
  PROFILE_SHELL=ksh
elif test -n "$FCEDIT"; then
  PROFILE_SHELL=ksh
elif test -n "$PS3"; then
  PROFILE_SHELL=unknown
else
  PROFILE_SHELL=sh
fi

It does not make fine distinctions between ksh88, ksh95, pdksh or mksh etc., but in more than ten years it has proven to work for me as designed on all the systems I were at home on (BSD, SunOS, Solaris, Linux, Unicos, HP-UX, AIX, IRIX, MicroStation, Cygwin.)

I don't see the need to check for csh in .profile, as csh sources other files at startup. Any script you write does not need to check for csh vs Bourne-heritage because you explicitly name the interpreter in the shebang line.

Jens
  • 69,818
  • 15
  • 125
  • 179
  • 1
    Thanks, that's exactly the sort of thing I was looking for. – DrHyde Jun 01 '11 at 10:31
  • 1
    http://www.in-ulm.de/~mascheck/various/whatshell/ looks pretty comprehensive. /via http://unix.stackexchange.com/questions/71121/determine-shell-in-script-during-runtime – clacke Apr 19 '13 at 10:32
16

Try to locate the shell path using the current shell PID:

ps -p $$

It should work at least with sh, bash and ksh.

ziu
  • 2,634
  • 2
  • 24
  • 39
  • 1
    Unfortunately all that does is tell me what the binary is called, not what type of shell it is. – DrHyde Mar 03 '11 at 10:52
6

If the reason you're asking is to try to write portable shell code, then spotting the shell type, and switching based on it, is an unreliable strategy. There's just too much variation possible.

Depending on what you're doing here, you might want to look at the relevant part of the autoconf documentation. That includes an interesting (and in some respects quite dismal) zoology of different shell aberrations.

For the goal of portable code, this section should be very helpful. If you do need to spot shell variants, then there might be some code buried in autoconf (or at least in one of the ./configure scripts it generates) which will help with the sniffing.

Norman Gray
  • 11,978
  • 2
  • 33
  • 56
3

You can use something like this:

shell=`cat /proc/$$/cmdline`
Jens
  • 69,818
  • 15
  • 125
  • 179
Šimon Tóth
  • 35,456
  • 20
  • 106
  • 151
  • 3
    That will only work on Linux and only if `/proc` is mounted/accessible. – Joachim Sauer Mar 02 '11 at 11:25
  • Only if procfs is available. You can probably achieve the same effect by looking at `$@`. – Maxim Egorushkin Mar 02 '11 at 11:26
  • 2
    Even on Linux with /proc it still doesn't work. All it does is tell you the path to the shell, not what the shell is. – DrHyde Mar 03 '11 at 10:57
  • @DrHyde What's the difference? `"/bin/bash"` is `bash`, `"/bin/sh"` is `sh`, `"/bin/zsh"` is `zsh`... – Šimon Tóth Mar 03 '11 at 11:00
  • 2
    On Linux, /bin/sh is quite often bash. This is also the case on at least some versions of OS X. – DrHyde Mar 03 '11 at 11:06
  • Apart form all the other critique, forking a cat process is just insane, when `read -r shell < /proc/$$/cmdline` would do the trick with about 1/1000 of the CPU cycles. – Jens Aug 15 '11 at 07:11
2

The system shell is the thing you see when you open up a fresh terminal window which is not set to something other than bash (assuming this is your default SHELL).

echo $SHELL

Generally, you can find out all the constants defined by running

set

If the output is a lot of stuff then run

set | less

so you can scroll it from the top of the command line or

set > set.txt

To save the output to a file.

Invoking a different interactive shell to bash in your terminal does not mean that your system shell gets changed to something else i.e. your system shell is set to bash although you invoke a csh shell from a bash shell just that one session.

The above means that typing /bin/csh or /bin/python in bash or whatever does not set the system shell to the shell you invoked, at all.

If you really want to see the SHELL constant change then you need to set it to something else. If successful you should see the new shell whenever you open a fresh terminal...

Magpie
  • 607
  • 2
  • 7
  • 26
  • As I pointed out in the question, $SHELL isn't set by all shells. – DrHyde Apr 22 '14 at 09:42
  • @DrHyde your post was impossible to read until I fixed it. In any case, I am explaining how you find the defined constants on your desktop. if you want to know what shell is set then you need to check $SHELL or give an example of why that does not work for you. – Magpie Apr 26 '14 at 22:54
  • Other people could read it just fine. But you want an example? OK, on this 'ere Mac, if I start in bash, which sets $SHELL, and then type 'csh' I end up in a different shell but with $SHELL unchanged. – DrHyde Apr 28 '14 at 22:05
  • @DrHyde ok I see why you are confused now. The above should clarify. – Magpie May 01 '14 at 04:10
  • SHELL is an indication of preference and not state. See http://unix.stackexchange.com/questions/45458/why-shell-doesnt-change-when-i-run-new-shell – Tom Duckering Feb 25 '15 at 16:35
  • @TomDuckering where did I say it was a state? – Magpie Feb 27 '15 at 12:57
  • @magpie Nowhere. My comment is a clarification and not a critique. – Tom Duckering Feb 28 '15 at 13:19
  • @TomDuckering if you want to edit the answer go ahead. – Magpie Mar 27 '15 at 20:49
1

Oh, I had this problem. :D

There is a quick hack, use ps -p $$ command to list the process with PID of the current running process -- which is your SHELL. This returns a string table structure, if you want, you can AWK, or SED the shell out...

Cipi
  • 11,055
  • 9
  • 47
  • 60
0

It's old thread but...

In GNU environment You can sh --help and get something like

BusyBox v1.23.2 (2015-04-24 15:46:01 GMT) multi-call binary.

Usage: sh [-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]

Unix shell interpreter

So, the first line is shell type =)

Arano-kai
  • 1
  • 4
  • That only tells you what `sh` is, not what your shell is. Consider this ... $ csh % sh --help GNU bash, version 3.2.57(1) ... GRARGH, STUPID WEBSITE FORMATTING – DrHyde Feb 11 '16 at 12:09
  • Try $(echo $0) --help ;) – Arano-kai Feb 11 '16 at 12:36
  • % $(echo $0) --help new line goes here stupid website formatting Illegal variable name. – DrHyde Feb 12 '16 at 13:31
  • It seems **tcsh** cannot expand $() notation, so more portable code will be `\`echo $0\` --help` or even `\`printf $0\` --help`. Also, note that **csh** is not sh compatible, so syntax may differ. – Arano-kai Feb 16 '16 at 08:48