628

I read that terminal is nothing but shell, and Unix provides different flavors of shells:

  • Bourne shell (sh)
  • C shell (csh)
  • TC shell (tcsh)
  • Korn shell (ksh)
  • Bourne Again shell (bash)

Questions:

  • When I open a terminal window, which shell is opened by default?
  • How do I check how many shells are installed?
  • How do I change the shell used from my account?
Joshua Besneatte
  • 4,643
  • 5
  • 21
  • 40
GMudide
  • 6,455
  • 3
  • 14
  • 7
  • 7
    [How to determine the current shell I'm working on?](http://stackoverflow.com/q/3327013/4023950) on [stackoverflow.com](http://stackoverflow.com/) – αғsнιη Feb 28 '15 at 04:16
  • @KasiyA This is also related to http://askubuntu.com/questions/87853/what-is-default-shell-for-terminal – d a i s y Feb 01 '17 at 09:20
  • Please note that terminal is interface to the shell (which at one point used to be actually physical interface), and shell is not terminal - it is a command interpreter. See also https://askubuntu.com/a/640105/295286 – Sergiy Kolodyazhnyy Apr 05 '19 at 01:34

9 Answers9

722

You can type the following command in your terminal to see which shell you are using:

echo $0

The result will look something similar to the below if you are using the bash (Bourne Again Shell) terminal:

-bash
kingmilo
  • 9,964
  • 1
  • 23
  • 33
  • 12
    is `0` an environment variable? – Mi_Onim Feb 22 '16 at 17:21
  • 69
    @Mi_Onim $0 is the name of the running process. If you use it inside of a shell then it will return the name of the shell. If you use it inside of a script, it will be the name of the script. – kingmilo Jun 26 '16 at 04:49
  • 2
    **NOTE**: this won't work for interactive `csh`. `% echo $0 No file for $0.` , but it does work for `tcsh` – Sergiy Kolodyazhnyy Sep 18 '16 at 12:43
  • 8
    Doesn't work if when one is symlink. Like `bash` as `sh` – Anwar Dec 06 '16 at 17:43
  • @Serg is there a way to find `csh` as well? or is that by design? – asgs Feb 06 '17 at 12:04
  • 14
    @Anwar makes a good point, after you get the shell name from `echo $0`, ``ls -l `which ` `` to see if it is symlinked to another shell binary. – JivanAmara Feb 10 '17 at 23:38
  • 2
    Does not work for `su - user` – Luis Muñiz Mar 14 '18 at 10:31
  • 2
    This is a bad solution. The name of a program can be changed in so many ways. – Daniel Santos Feb 04 '19 at 23:17
  • 5
    does not work for fish shell – masukomi Jun 20 '19 at 18:27
  • Accessed in a shell function named `myfunc`, `$0` is `bash` for bash, but `myfunc` for zsh. – frozen-flame Jul 30 '19 at 10:30
  • This is a brittle solution which will break in sourced scripts. – Alexander Revo Jan 07 '20 at 12:24
  • @AlexanderRevo well I guess it’s a good thing then that the question wasn’t centered around “sourced” scripts ;) – kingmilo Jan 07 '20 at 13:39
  • 1
    @kingmilo while you are technically not wrong, a solution that only works in certain scenarios would benefit from a disclaimer. – Alexander Revo Jan 07 '20 at 14:46
  • @AlexanderRevo I understand your point, but the user asking the question was the same user who accepted my answer, I don’t have control over that. If the user is satisfied with an answer then the entire purpose of this forum has been achieved. If you decide to mark the answer down, that’s fine, and encouraged if you don’t agree, I’m not disputing that. I am disputing your comment though. You have asked that I add a disclaimer to my answer, yet you have submitted a comment which doesn’t fit the context of the question/answer at all. I hope you manage to see the irony in this all =] – kingmilo Jan 07 '20 at 14:56
  • 1
    @masukomi for fish shell, check the next answer down, which recommends `echo $SHELL` or checking PIDs – Mike B May 17 '20 at 20:47
  • This doesn't work with `zsh` during the execution of a `source` command. To confirm this, try creating the file `foo.sh` with the following content `echo $0` and then create `main.sh` with the following content `echo $0 && source ./foo.sh` and you will see that the output of executing `zsh main.sh` is `zsh.sh\n./foo.sh`. That's why I state that `$0` doesn't work with `zsh`. – doltes Nov 16 '20 at 07:49
  • @mblakesley that does not work for non POSIX shells like fish - and echo $SHELL bears no connection with the actual shell you are running – mmmmmm Jan 26 '21 at 16:15
  • Worth noting if you have more than one Bash installed (which may be common e.g. on macOS which ships with outdated Bash by default), then this approach does not show you which one you are running - if you need that, I have just added an answer which does. – MikeBeaton Jul 02 '21 at 09:36
  • it is show me this on ArchLinux /usr/bin/zsh – Ahmad Moghazi Sep 21 '21 at 02:06
205

To find the shell you have on the default environment you can check the value of the SHELL environment variable:

echo $SHELL

To find the current shell instance, look for the process (shell) having the PID of the current shell instance.

To find the PID of the current instance of shell:

echo "$$"

Now to find the process having the PID:

ps -p <PID>

Putting it together:

ps -p "$$"
heemayl
  • 90,425
  • 20
  • 200
  • 267
  • 51
    $SHELL is the default shell for the system (or user), which is usually (but not necessarily) the shell that is actually being used at any given moment. – kingmilo Feb 28 '15 at 04:13
  • 1
    @kingmilo: Right you are, answer modified. – heemayl Feb 28 '15 at 04:24
  • I found this pretty useful when switching to a user through 'su - ', e.g. for setting up postgres, jenkins, ... – bully Oct 07 '15 at 11:20
  • 3
    `echo $SHELL` gave me `/bin/csh` and `ps -p $$` gave me `22673 pts/1 00:00:00 bash`. Kingmilo explained (above) why they are not the same. – 18446744073709551615 Oct 30 '17 at 10:32
  • @18446744073709551615 I have not said either that they are the same. Please read the answer carefully again; note the _default_ and _current_ wordings. – heemayl Oct 30 '17 at 13:34
  • @heemayl I already did. Of course when the code gives unexpected results, one reads the text near it. It is logical. – 18446744073709551615 Nov 01 '17 at 08:30
  • for a shell script to start a new session – Marcello de Sales Nov 12 '19 at 21:09
  • 4
    To grab ONLY the shell name for the current shell in a way portable between gnu & bsd ps versions, this works well: `ps -cp "$$" -o command=""` – James Tomasino Jan 07 '20 at 22:37
  • 1
    thank you @James Tomasino that worked the best! – Robert Houghton Feb 06 '20 at 01:26
  • 1
    "$$" is not the pid in fish shell "$fish_pid" is. Fish will let you know this but if you don't know you're in fish it's an annoying error that makes this particular method unreliable for determining your shell. – masukomi May 21 '20 at 14:55
  • Funny, I did `kill $(echo "$$")` and my shell is still running – theX Oct 04 '20 at 23:43
  • doing a "./test.sh" on the command line will resolve to reporting "test.sh" as the invoked command. - in this case the solution is not really working. – Alexander Stohr May 17 '21 at 08:03
  • @masukomi mentions that fish will let you know "$$" is not the pid; but in my version of fish it says `fish: $$ is not the pid. In fish, please use %self.` But at least at that point, I know I'm using a fish shell, not bash, as `echo $SHELL` would lead me to believe. – hlongmore Oct 15 '22 at 05:27
  • does not work with fish shell – Sergei G Mar 18 '23 at 03:01
  • When I run `ps -cp "$$" -o command=""` as a shell command from the GHCI REPL, I get `ps` as the output instead of the shell it uses. – Miguel Guthridge Jun 08 '23 at 01:46
60

$SHELL gives you the default shell. $0 gives you the current shell.

For example: I have bash as my default shell, which I use for my Terminal App. But for my iTerm2 app, I use the command as the window opens: /bin/ksh.

So my $0 gives me /bin/ksh on iTerm2. $SHELL gives me /bin/bash on iTerm2. $0,$SHELL gives me /bin/bash on Terminal

muru
  • 193,181
  • 53
  • 473
  • 722
thenakulchawla
  • 723
  • 5
  • 10
  • 2
    This is a nice disambiguation of the other top-voted answers. Thank you. – Michael Hoffmann Feb 14 '18 at 18:58
  • 1
    For me, I have zsh installed and it's the current default, to change to bash, all I have to do type `bash` in the terminal. To switch back to zsh, type `zsh` – Yousuf Azad Feb 27 '19 at 11:11
  • 2
    You don't want to keep going back and forth that way because you stack up shell within shell within shell, and a fresh context within each. In general it's best to type ctrl-d or exit to return to the previous shell. – Phill Apley Apr 16 '21 at 19:21
  • Best answer, should be chosen as answer. Agree to yousuf Azad on changing shell, but also agree to stacking issue indicated by Phill Apley. My default is also `zsh`, but to switch I type `bash`, and to return back I can simply do `exit` or ctrl + D – Sanjay May 21 '21 at 04:55
24

The other answers tend to be using shell specific features, but we are trying to discover which shell we are using, so they assume the answer to the problem. For example none of the answers will work on fish.

sh -c 'ps -p $$ -o ppid=' | xargs ps -o comm= -p

Instead use the $$ syntax in an invocation of sh, but then we are looking for the PPID not the PID. Use the PPID to find the cmd.

sh -c 'ps -p $$ -o ppid=' | xargs -I'{}' readlink -f '/proc/{}/exe'

Thanks for improvement @muru

Evan Benn
  • 339
  • 2
  • 4
  • 2
    You ca use `ppid=`/`cmd=`to omit the headers (and so the `tail -1`s), and consider looking at `/proc/.../exe` to see what file is being run (since the `cmd` output can be manipulated by whatever ran the shell). – muru Apr 06 '18 at 04:07
  • 3
    Apparently this does not work in busybox, due to non posix compliance: ref: https://github.com/broadinstitute/cromwell/pull/3561#pullrequestreview-116186537 – Evan Benn Apr 30 '18 at 05:04
  • What does your first code block exemplify? – Andreas Feb 11 '20 at 22:29
  • 1
    this solution solves the problem of assuming the shell but introduces the problem of assuming the OS. The BSD version of readlink shipped with macOS (and presumably other BSD Distros) uses -f to specify "format" which is a printf style string that must start and end with % and has a variety of templating options. – masukomi May 21 '20 at 15:02
  • Great answer, @EvanBenn, thanks! Here is a tiny modification to allow it to work with shells like `BusyBox`, where the `-p` arg to `ps` isn't supported, and where there aren't a whole lot of other utilities like `cut` to help. Code: `set -- $(ps -o pid,ppid | grep -E "^ *$$"); readlink -f "/proc/${2}/exe"`. I'm using your method to determine the shells used on a bunch of "free online Linux shell" websites, and it's great! – Sean Aug 02 '21 at 00:25
  • @Sean add it in an edit if you like! – Evan Benn Aug 04 '21 at 01:56
  • I tried running @Sean's command, and fish complained at me, for multiple reasons. Granted I'm not running BusyBox, but at least it complained in a way that I know I'm running fish. The second command in the original answer worked for me, on an Ubuntu-based system. – hlongmore Oct 15 '22 at 05:30
  • @EvanBenn, @hlongmore : If you want to support odd shells like `fish` and `csh` and you still want to get the parent shell's executable path (the PPID rather than the PID), the following will work: `test ! -z "$shell" && set empty && set pid="$$$empty" || test ! -z "$fish_pid" && set pid "$fish_pid" || export pid="$$$empty"; ps -o pid,ppid | grep -E "^ *$pid" | grep -o '[^ ]*$' | xargs -I ppid readlink -f "/proc/ppid/exe" | cat` – Sean Apr 08 '23 at 02:39
  • If you prefer to get the executable path of the _current_ shell, just change it to: `test ! -z "$shell" && set empty && set pid="$$$empty" || test ! -z "$fish_pid" && set pid "$fish_pid" || export pid="$$$empty"; readlink -f "/proc/$pid/exe" | cat` – Sean Apr 08 '23 at 02:40
14

The original post asked three questions. The answers given do cover the first question, "When I open a terminal window, which shell is opened by default?" They also answer a question which was NOT asked, namely "How can I find out which shell is currently running in the terminal?" However, as far as I can see nobody has answered either the second or third questions originally asked, namely "How do I check how many shells are installed?" and "How do I change the shell used from my account?"

  • To answer "How do I check how many shells are installed?" the following command will list all the available shells:

    cat /etc/shells
    

    For example, on a default installation of Ubuntu 18.10 this gives:

    # /etc/shells: valid login shells
    /bin/sh
    /bin/dash 
    /bin/bash
    /bin/rbash
    

    However, by default sh is a symbolic link to dash, while rbash links to bash with the option -r ("restricted bash") so there are actually only two shells, not four as the above list suggests. The following command will show you whether any of the listed shells are in fact symbolic links, and if so where they link to: ls -l /bin

  • Now for the question "How do I change the shell used from my account?" Assuming this means "How do I permanently change the default shell that a terminal will use", there is an answer here.

Pablo Bianchi
  • 14,308
  • 4
  • 74
  • 117
Michael D
  • 201
  • 3
  • 7
13

To know which is the default shell for your user, you can run:

echo "$SHELL"

For example if you're using Bash you should get the following output:

/bin/bash

If you didn't change any configuration it should be Bash since Bash it's the default shell on Ubuntu.

kos
  • 35,535
  • 13
  • 101
  • 151
  • /bin/sh is the Shell Command Language and not the Bourne Shell, please edit your answer. – kingmilo Feb 28 '15 at 04:07
  • @kingmilo There's no `/bin/sh` reference in my answer – kos Feb 28 '15 at 04:12
  • @kol there was before edit. Please also note $SHELL is the default shell for the system (or user), which is usually (but not necessarily) the shell that is actually being used at any given moment. – kingmilo Feb 28 '15 at 04:14
  • @kingmilo Please note that the question is "when i open terminal which shell is opened by default???" and that the answer is "If you didn't change any configuration it should be `Bash`, because that's the default shell on Ubuntu", so the answer fits the question – kos Feb 28 '15 at 04:22
  • 1
    @kingmilo Reading the answer again i think i understand what is your concern, probably i didn't express myself well. I clarified the meaning of "currently" in my answer – kos Feb 28 '15 at 04:49
  • The answer to use `ps -p "$$"` works in bash and possibly other shells but this will not work with fish ([Friendly Interactive SHell](https://fishshell.com/)). In fish you should run `ps -p %self`. So I am not sure there is any one command that you can run to tell you what shell you are in. You may need to try both of these and possibly other commands to determine that. – frederickjh Aug 17 '16 at 20:51
  • 2
    @frederickjh fish is a bit of an odd one out here. The `$$` variable is actually [defined by POSIX](http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_05_02) and will work on the vast majority of shells. Fish has decided not to follow the standard here so I think it's fair to ignore it. I can confirm that `$$` works as expected in sh, dash, bash, zsh, ksh, ash, tcsh and csh. In fact, off the top of my head I can't think of any other shell except fish where it doesn't work. – terdon Aug 18 '16 at 09:02
4

You may not want to know the current shell's name (e.g. -bash, bash, zsh, etc., from echo $0), nor default shell's executable path (from echo $SHELL), but rather the current shell's executable path (especially useful e.g. if you have more than one version of Bash installed).

To do this you can use lsof -p "$$" or with some extra coding to extract just the required info:

lsof -p "$$" | grep -m 1 txt | xargs -n 1 | tail -n 1

Example output for Bash installed via Homebrew:

/usr/local/Cellar/bash/5.1.8/bin/bash

or for Zsh:

/bin/zsh

The above is different from echo $SHELL, both because the above is for the shell which is currently running rather than the user's default shell, and also because the above gives the executable after any symlinks have been expanded. E.g. for the same Bash install as above, echo $SHELL gives /usr/local/bin/bash.

EDIT: If you need to allow for possible space characters in the shell's path, use lsof -p "$$" | grep -m 1 txt | xargs -n 1 | tail -n +9 | xargs instead.

MikeBeaton
  • 213
  • 1
  • 9
2

To address your third question, "How do I change the shell used from my account?", the answer is to use chsh.

There are two modes:

  • interactive, and;
  • non-interactive.

From Changing Shells - Changing your login shell which is permanent, and paraphrasing it slightly:

You will use a program called chsh. There is a interactive method and non-interactive method. Type the following into your terminal:

INTERACTIVE METHOD

$ chsh

This results in a brief dialog in which the user is prompted first for their password and then for the full path of the desired new shell.

Caution should be exercised when changing one's default shell because it is possible to make an error that only the root user (i.e., system administrator) can repair (although it should be easy for a skilled user to repair it on a home system). In particular, it is important to first test the shell temporarily in the current session and then to make certain that a valid shell name is being entered when making the permanent change.

NON-INTERACTIVE METHOD

I will use csh as again an example.

$ chsh -s /bin/csh

The -s sets it for you without having to go into the editor to do it.

Once this is executed successfully, then echo $SHELL will still say that you are in the same shell as before. However, you need to log out and back in for the change to take effect. Now do echo $SHELL. You should see it shows the new shell.

Greenonline
  • 2,030
  • 8
  • 20
  • 27
0

In one of the servers I connect to, the login shell is /bin/sh which is a symlink to /bin/bash

Most answers here will give sh, which would make the OP consider it's Bourne shell and not GNU bash, except this one that gives /bin/bash

Another option that works for this case is:

$ echo $SHELL
/bin/sh

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 May 31 16:15 /bin/sh -> bash

$ /bin/sh --help
GNU bash, version 4.2.10(1)
Usage:  /bin/sh [GNU long option] [option] ...
        /bin/sh [GNU long option] [option] script-file ...
golimar
  • 127
  • 7
  • Possibly the answer I've just added also addresses this issue? I'm not quite sure how cross-system it is, so would be interested to know how it works for you on that server. :) – MikeBeaton Jul 02 '21 at 09:13