796

How can I determine the current shell I am working on?

Would the output of the ps command alone be sufficient?

How can this be done in different flavors of Unix?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
josh
  • 13,793
  • 12
  • 49
  • 58
  • 9
    Testing for particular capabilities (e.g. does it do `!` substitution?) is probably more portable than finding the name of the shell. Local custom might have you running something named `/bin/sh` which could actually be ash, dash, bash, etc. – msw Jul 24 '10 at 21:38
  • 2
    @msw: Seems like a good comment except it leaves me wondering "how?". – Brent Bradburn Oct 24 '12 at 17:41
  • It appears that there is no simple answer to this question. If we can't _query_ the shell, maybe the better approach is to always _specify_ the shell. I'm not sure that this is always possible, but maybe it is more easily accomplished than people generally assume. – Brent Bradburn Oct 24 '12 at 17:49
  • This might help --> http://opensourceforgeeks.blogspot.in/2013/05/how-to-find-current-shell-in-linux.html – Aniket Thakur Feb 21 '14 at 06:14
  • @Aniket, not so much help as you might think - that's only interested in *interactive* shell processes. – Toby Speight Feb 17 '20 at 15:50

29 Answers29

953
  • There are three approaches to finding the name of the current shell's executable:

    Please note that all three approaches can be fooled if the executable of the shell is /bin/sh, but it's really a renamed bash, for example (which frequently happens).

    Thus your second question of whether ps output will do is answered with "not always".

    1. echo $0 - will print the program name... which in the case of the shell is the actual shell.

    2. ps -ef | grep $$ | grep -v grep - this will look for the current process ID in the list of running processes. Since the current process is the shell, it will be included.

      This is not 100% reliable, as you might have other processes whose ps listing includes the same number as shell's process ID, especially if that ID is a small number (for example, if the shell's PID is "5", you may find processes called "java5" or "perl5" in the same grep output!). This is the second problem with the "ps" approach, on top of not being able to rely on the shell name.

    3. echo $SHELL - The path to the current shell is stored as the SHELL variable for any shell. The caveat for this one is that if you launch a shell explicitly as a subprocess (for example, it's not your login shell), you will get your login shell's value instead. If that's a possibility, use the ps or $0 approach.


  • If, however, the executable doesn't match your actual shell (e.g. /bin/sh is actually bash or ksh), you need heuristics. Here are some environmental variables specific to various shells:
  • $version is set on tcsh

  • $BASH is set on bash

  • $shell (lowercase) is set to actual shell name in csh or tcsh

  • $ZSH_NAME is set on zsh

  • ksh has $PS3 and $PS4 set, whereas the normal Bourne shell (sh) only has $PS1 and $PS2 set. This generally seems like the hardest to distinguish - the only difference in the entire set of environment variables between sh and ksh we have installed on Solaris boxen is $ERRNO, $FCEDIT, $LINENO, $PPID, $PS3, $PS4, $RANDOM, $SECONDS, and $TMOUT.

Benjamin Loison
  • 3,782
  • 4
  • 16
  • 33
DVK
  • 126,886
  • 32
  • 213
  • 327
  • ${.sh.version} is set on ksh93 – fpmurphy Jul 24 '10 at 22:20
  • 24
    `ps -p $$` as [Matthew Slattery](http://stackoverflow.com/questions/3327013/how-to-determine-the-current-shell-im-working-on/3327108#3327108) points out. For `ksh`: `echo $KSH_VERSION` or `echo ${.sh.version}`. – Dennis Williamson Jul 24 '10 at 22:29
  • @Dennish - my ksh right now doesn't have KSH_VERSION set. and `echo ${.sh.version}` returns "Bad Substitution". See my solution above – DVK Jul 24 '10 at 22:41
  • @fpmurphy whatever ksh we have installed on Solaris boxen at work, obviously predates ksh93 as it odesn't have that set. Matter of fact, the ONLY difference in entire set of envionmental variables between `sh` and `ksh` is `$ERRNO`, `$FCEDIT`, `$LINENO`, `$PPID`, `$PS3`, `$PS4`, `$RANDOM`, `$SECONDS`, `$TMOUT`. – DVK Jul 24 '10 at 22:44
  • @DVK Currently Solaris has a highly customized version of ksh88. The POR is to move to ksh93 for the next release. See http://hub.opensolaris.org/bin/view/Project+ksh93-integration/ for more information. – fpmurphy Jul 26 '10 at 14:45
  • None of this works if trying to access SHELL type from a python script. – Viks Jan 20 '14 at 19:11
  • This is confusing: `$ ps | grep sh` `25736 pts/1 00:00:00 sh` `25740 pts/1 00:00:00 bash` ... where `/bin/bash` is an executable, and `/bin/sh` points to `dash` – a different ben Sep 28 '14 at 23:45
  • @Viks - it would if you write a shell script to do so – DVK Jun 12 '15 at 16:03
  • In zsh, `echo $0` prints the name of the script, not the name of the shell. – Dan Stahlke Sep 10 '15 at 00:18
  • 3
    _“`ps -ef | grep …` … This is not 100% reliable as …”_    Using a simple regular expression via `egrep` or `grep -e` can easily bring the reliability up to for-all-intents-and-purposes 100%: `ps -ef | egrep "^\s*\d+\s+$$\s+"`.  The `^` makes sure we're starting from the beginning of the line, the `\d+` eats up the UID, the `$$` matches the PID, and the `\s*` and `\s+` account for & ensure whitespace between the other parts. – Slipp D. Thompson Mar 05 '16 at 02:57
  • for the heuristics +1. Really helpful – Anwar Dec 06 '16 at 17:44
  • 2
    @SlippD.Thompson didn't work in GNU/Linux. But this seem to work: `ps -ef | awk '$2==pid' pid=$$` – jarno Jan 14 '17 at 14:18
  • `pgrep` is better for grepping thru processes – leetbacoon Nov 07 '19 at 16:34
  • None of those 3 give you *this* shell when running an executable script (or, more likely, a file sourced therefrom). The heuristic approach is then the only reasonable one (and arguably more useful: test the features you need, and use what works). – Toby Speight Feb 17 '20 at 14:53
  • None of the above works in busybox. There, you can get busybox shell by something like: `/ # busybox ash ash: applet not found / # busybox hush / #` – Angelo Dureghello Mar 08 '20 at 11:58
  • `echo $SHELL` is IMHO the most useful and logical approach, because it exactly tells which shell is running. – Markus Zeller Sep 23 '20 at 08:03
  • $SHELL isn't available in powershell, is there an alternative for that case? – openCivilisation Jan 14 '22 at 05:02
  • `$SHELL` is the wrong approach as it is set by `login(1)` not the shell. If you launch a different shell (e.g. via `sudo -l`) `$SHELL` will still be set to the original user's login shell. – blarf Apr 07 '22 at 18:40
  • `$SHELL` is completely useless for determining the current shell: https://stackoverflow.com/questions/74376285/what-is-the-purpose-of-shell – William Pursell Nov 10 '22 at 18:19
130

ps -p $$

should work anywhere that the solutions involving ps -ef and grep do (on any Unix variant which supports POSIX options for ps) and will not suffer from the false positives introduced by grepping for a sequence of digits which may appear elsewhere.

Matthew Slattery
  • 45,290
  • 8
  • 103
  • 119
  • 16
    Some shells have their own builtin version of `ps` which may not understand `-p` so you may need to use `/bin/ps -p $$`. – Dennis Williamson Jul 24 '10 at 22:32
  • 16
    All the shells I'm familiar with understand `$$` except for `fish` with which you would have to use `ps -p %self`. – Dennis Williamson Jul 24 '10 at 22:48
  • 3
    Actually, you shouldn't rely on a hard paths such as `/bin/ps`. `ps` could easily (actually it is quite normal nowadays) be installed in `/usr/bin`. `$(which ps) -p $$` is a better way. Of course, this will not work in fish, and possibly some other shells. I think it is `(which ps) -p %self` in fish. – Xyz Nov 06 '14 at 12:49
  • 2
    In some minimal systems like a debian-slim docker container, ps might not be there. In that case this approachs still works: `readlink /proc/$$/exe` – mxmlnkn Feb 28 '19 at 14:16
  • 1
    if your `sh` is emulated by `bash`, ps -p give you `/usr/bin/bash` even you run it as `sh` – Ding-Yi Chen Jun 26 '19 at 00:00
  • 1
    `$$` is the [Process ID of the script itself](http://tldp.org/LDP/abs/html/internalvariables.html#PROCCID). And `ps $$` already works in many cases. – HongboZhu Jul 03 '19 at 13:42
  • @Xyz instead of `$(which ps) -p $$`, why not just use `command ps -p $$` or `env ps -p $$`? – tmillr Mar 03 '23 at 21:23
  • Or for easier parsing: `ps -o comm -p $$`, which prints only the relevant column (although still two lines). It's [still POSIX](http://www.opengroup.org/onlinepubs/009695399/utilities/ps.html). Possibly modify for other ways to get the correct `ps`, according to taste. @9265740/tmillr 's `command ps` [should call the POSIX `ps`](https://pubs.opengroup.org/onlinepubs/9699919799/). Also note that POSIX does not specify the path to `ps`, or any other executable, and also doesn't require `/proc/`. Final note: `/proc/` doesn't exist on macOS, and isn't - I think - enabled by default on BSD. – Carl Jul 07 '23 at 18:50
54

Try

ps -p $$ -oargs=

or

ps -p $$ -ocomm=
Monolo
  • 18,205
  • 17
  • 69
  • 103
Nahuel Fouilleul
  • 18,726
  • 2
  • 31
  • 36
  • 6
    This is a nice short one. I was using myself `ps -o fname --no-headers $$`. – Anne van Rossum Mar 08 '14 at 16:45
  • Thanks. I found this the best option to use in a script to guard bash specific commands `test \`ps -p $$ -ocomm=\` == "bash" && do_something_that_only_works_in_bash`. (The next line in my script has the equivalent for csh.) – craq Dec 11 '14 at 14:38
  • 2
    I've found that if you do this from within a subshell then it can lead to spurious extra lines by matching the parent's PID as well as the actual shell process. For this, I use `-q` instead of `-p`: `SHELL=$(ps -ocomm= -q $$)` – Steve Dec 28 '17 at 23:09
47

If you just want to ensure the user is invoking a script with Bash:

if [ -z "$BASH" ]; then echo "Please run this script $0 with bash"; exit; fi

or ref

if [ -z "$BASH" ]; then exec bash $0 ; exit; fi
Nam G VU
  • 33,193
  • 69
  • 233
  • 372
Peter Lamberg
  • 8,151
  • 3
  • 55
  • 69
  • 2
    This should be the one closer to the top. Thanks a lot. – Alex Skrypnyk Sep 17 '14 at 04:15
  • 8
    It shouldn't be closer to top, because it doesn't answer the question at all. If the question would be "How to check if script is running under bash", I vote for it. – David Ferenczy Rogožan Oct 14 '14 at 11:24
  • 5
    @DawidFerenczy - This question is the top result when you search for that phrase though. In the long run, I think it's much more important that answers answer what people are looking for rather than answer what the original question was about. – ArtOfWarfare Jun 05 '17 at 21:11
  • 4
    In addition, the variable $BASH _is_ defined under tcsh if the tcsh is invoked from bash – 18446744073709551615 Apr 16 '18 at 11:03
  • This is very useful, thank you. Just adapted it a bit, putting this as the second line after `#!/bin/bash`: `if [ ! -n "$BASH" ] ;then exec bash $0; fi`. With this line the script is run using bash even if started using ksh or sh. My use case doesn't need command line arguments, but they could be added after `$0` if necessary. – joanis Jun 05 '19 at 15:04
  • I run my script using `sh – Franz Wong May 26 '22 at 02:02
  • This is most useful for me. – Nam G VU Feb 08 '23 at 15:27
24

You can try:

ps | grep `echo $$` | awk '{ print $4 }'

Or:

echo $SHELL
karlphillip
  • 92,053
  • 36
  • 243
  • 426
  • 7
    What's the point of grep followed by awk, when `/pattern/ { action }` will do? – Jens Apr 15 '13 at 11:18
  • # in zshell alias shell='echo ${SHELL:t}' – SergioAraujo Jan 13 '14 at 18:09
  • 9
    `$SHELL` environment variable contains a shell, which is configured as default for a current user. It doesn't reflect a shell, which is currently running. Also it's better to use `ps -p $$` than grepping $$ because of false positives. – David Ferenczy Rogožan Oct 14 '14 at 11:16
  • The $SHELL env. variable points to the 'parent' shell, as specified in the POSIX spec: **SHELL** This variable shall represent a pathname of the user's preferred command language interpreter. Therefore the value of $SHELL may not be the current shell. – Theo Sep 04 '15 at 21:42
  • all within `awk`, `ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'` – go2null Sep 21 '17 at 05:12
  • SHELL does not refer to either the current shell, nor the parent shell. https://stackoverflow.com/questions/74376285/what-is-the-purpose-of-shell – William Pursell Nov 10 '22 at 18:19
23

$SHELL need not always show the current shell. It only reflects the default shell to be invoked.

To test the above, say bash is the default shell, try echo $SHELL, and then in the same terminal, get into some other shell (KornShell (ksh) for example) and try $SHELL. You will see the result as bash in both cases.

To get the name of the current shell, Use cat /proc/$$/cmdline. And the path to the shell executable by readlink /proc/$$/exe.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
sr01853
  • 6,043
  • 1
  • 19
  • 39
19

There are many ways to find out the shell and its corresponding version. Here are few which worked for me.

Straightforward

  1. $> echo $0 (Gives you the program name. In my case the output was -bash.)
  2. $> $SHELL (This takes you into the shell and in the prompt you get the shell name and version. In my case bash3.2$.)
  3. $> echo $SHELL (This will give you executable path. In my case /bin/bash.)
  4. $> $SHELL --version (This will give complete info about the shell software with license type)

Hackish approach

$> ******* (Type a set of random characters and in the output you will get the shell name. In my case -bash: chapter2-a-sample-isomorphic-app: command not found)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Devang Paliwal
  • 291
  • 2
  • 4
13

I have a simple trick to find the current shell. Just type a random string (which is not a command). It will fail and return a "not found" error, but at start of the line it will say which shell it is:

ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user5659949
  • 131
  • 1
  • 2
  • 6
    No good in a script. `echo 'aaaa' > script; chmod +x script; ./script` gives `./script.sh: 1: aaaa: not found` – slim Sep 19 '16 at 14:39
12

ps is the most reliable method. The SHELL environment variable is not guaranteed to be set and even if it is, it can be easily spoofed.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ennuikiller
  • 46,381
  • 14
  • 112
  • 137
  • 16
    +1 $SHELL is the default shell for programs that need to spawn one. It doesn't necessarily reflect the shell that's currently running. – Jim Lewis Jul 24 '10 at 21:43
8

I have tried many different approaches and the best one for me is:

ps -p $$

It also works under Cygwin and cannot produce false positives as PID grepping. With some cleaning, it outputs just an executable name (under Cygwin with path):

ps -p $$ | tail -1 | awk '{print $NF}'

You can create a function so you don't have to memorize it:

# Print currently active shell
shell () {
  ps -p $$ | tail -1 | awk '{print $NF}'
}

...and then just execute shell.

It was tested under Debian and Cygwin.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
David Ferenczy Rogožan
  • 23,966
  • 9
  • 79
  • 68
  • As of my setup (Cygwin | Windows 7) your answer is the best one, and ***ps -p $$ | tail -1 | gawk '{print $NF}'*** works even from cmd without $bash. Please note gawk instead of awk, as awk works only from bash. – WebComer May 22 '18 at 12:46
  • @WebComer Sorry, I'm not sure what you mean by "_works even from cmd without $bash_". Even if you would have Windows ports of `ps`, `tail` and `gawk`, cmd doesn't define `$$` as it's PID so it definitely cannot work under the plain cmd. – David Ferenczy Rogožan Mar 11 '19 at 12:43
  • Why not simply `ps -p$$ -o comm=`? POSIX says that specifying all headers empty suppresses the header completely. We're still failing (like all the `ps` answers) when we're sourced by a directly executed script (e.g. `#!/bin/sh`). – Toby Speight Feb 05 '20 at 09:04
  • this doesn't work with busybox ps (which is used on alpine) – bernstein Jul 30 '21 at 13:06
6

The following will always give the actual shell used - it gets the name of the actual executable and not the shell name (i.e. ksh93 instead of ksh, etc.). For /bin/sh, it will show the actual shell used, i.e. dash.

ls -l /proc/$$/exe | sed 's%.*/%%'

I know that there are many who say the ls output should never be processed, but what is the probability you'll have a shell you are using that is named with special characters or placed in a directory named with special characters? If this is still the case, there are plenty of other examples of doing it differently.

As pointed out by Toby Speight, this would be a more proper and cleaner way of achieving the same:

basename $(readlink /proc/$$/exe)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
vadimbog
  • 386
  • 3
  • 9
  • 4
    This just errors on all Unices that don't provide `/proc`. Not all the world's a Linux box. – Jens Oct 28 '14 at 06:12
  • 6
    And if you *are* on Linux, we'd prefer `basename $(readlink /proc/$$/exe)` to `ls`+`sed`+`echo`. – Toby Speight Jan 14 '16 at 20:02
  • 2
    This will give the name of the actual *executable*, not the actual *shell*. When the actual shell is linked as a busybox applet, say `ash -> /bin/busybox`, this will give /bin/busybox. – stepse Mar 13 '17 at 12:12
6

My variant on printing the parent process:

ps -p $$ | awk '$1 == PP {print $4}' PP=$$

Don't run unnecessary applications when AWK can do it for you.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Matthew Stier
  • 61
  • 1
  • 1
4

Provided that your /bin/sh supports the POSIX standard and your system has the lsof command installed - a possible alternative to lsof could in this case be pid2path - you can also use (or adapt) the following script that prints full paths:

#!/bin/sh
# cat /usr/local/bin/cursh
set -eu
pid="$$"

set -- sh bash zsh ksh ash dash csh tcsh pdksh mksh fish psh rc scsh bournesh wish Wish login

unset echo env sed ps lsof awk getconf

# getconf _POSIX_VERSION  # reliable test for availability of POSIX system?
PATH="`PATH=/usr/bin:/bin:/usr/sbin:/sbin getconf PATH`"
[ $? -ne 0 ] && { echo "'getconf PATH' failed"; exit 1; }
export PATH

cmd="lsof"
env -i PATH="${PATH}" type "$cmd" 1>/dev/null 2>&1 || { echo "$cmd not found"; exit 1; }

awkstr="`echo "$@" | sed 's/\([^ ]\{1,\}\)/|\/\1/g; s/ /$/g' | sed 's/^|//; s/$/$/'`"

ppid="`env -i PATH="${PATH}" ps -p $pid -o ppid=`"
[ "${ppid}"X = ""X ] && { echo "no ppid found"; exit 1; }

lsofstr="`lsof -p $ppid`" || 
   { printf "%s\n" "lsof failed" "try: sudo lsof -p \`ps -p \$\$ -o ppid=\`"; exit 1; }

printf "%s\n" "${lsofstr}" | 
   LC_ALL=C awk -v var="${awkstr}" '$NF ~ var {print $NF}'
carlo
  • 41
  • 1
  • 1
    this works in fish! but for me, fails in bash, because of the `-i` (-> ignore environment) option to `env` in the line where you check for `lsof` being available. it fails with: `env -i PATH="${PATH}" type lsof` -> `env: ‘type’: No such file or directory` – hoijui Mar 14 '18 at 07:12
4

My solution:

ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1

This should be portable across different platforms and shells. It uses ps like other solutions, but it doesn't rely on sed or awk and filters out junk from piping and ps itself so that the shell should always be the last entry. This way we don't need to rely on non-portable PID variables or picking out the right lines and columns.

I've tested on Debian and macOS with Bash, Z shell (zsh), and fish (which doesn't work with most of these solutions without changing the expression specifically for fish, because it uses a different PID variable).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
wickles
  • 49
  • 3
3

Please try this helpful command.

echo $SHELL
Pratik Gaurav
  • 661
  • 7
  • 8
2

If you just want to check that you are running (a particular version of) Bash, the best way to do so is to use the $BASH_VERSINFO array variable. As a (read-only) array variable it cannot be set in the environment, so you can be sure it is coming (if at all) from the current shell.

However, since Bash has a different behavior when invoked as sh, you do also need to check the $BASH environment variable ends with /bash.

In a script I wrote that uses function names with - (not underscore), and depends on associative arrays (added in Bash 4), I have the following sanity check (with helpful user error message):

case `eval 'echo $BASH@${BASH_VERSINFO[0]}' 2>/dev/null` in
    */bash@[456789])
        # Claims bash version 4+, check for func-names and associative arrays
        if ! eval "declare -A _ARRAY && func-name() { :; }" 2>/dev/null; then
            echo >&2 "bash $BASH_VERSION is not supported (not really bash?)"
            exit 1
        fi
        ;;
    */bash@[123])
        echo >&2 "bash $BASH_VERSION is not supported (version 4+ required)"
        exit 1
        ;;
    *)
        echo >&2 "This script requires BASH (version 4+) - not regular sh"
        echo >&2 "Re-run as \"bash $CMD\" for proper operation"
        exit 1
        ;;
esac

You could omit the somewhat paranoid functional check for features in the first case, and just assume that future Bash versions would be compatible.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alex Dupuy
  • 5,984
  • 3
  • 39
  • 35
2

None of the answers worked with fish shell (it doesn't have the variables $$ or $0).

This works for me (tested on sh, bash, fish, ksh, csh, true, tcsh, and zsh; openSUSE 13.2):

ps | tail -n 4 | sed -E '2,$d;s/.* (.*)/\1/'

This command outputs a string like bash. Here I'm only using ps, tail, and sed (without GNU extesions; try to add --posix to check it). They are all standard POSIX commands. I'm sure tail can be removed, but my sed fu is not strong enough to do this.

It seems to me, that this solution is not very portable as it doesn't work on OS X. :(

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
rominf
  • 2,719
  • 3
  • 21
  • 39
1

This is not a very clean solution, but it does what you want.

# MUST BE SOURCED..
getshell() {
    local shell="`ps -p $$ | tail -1 | awk '{print $4}'`"

    shells_array=(
    # It is important that the shells are listed in descending order of their name length.
        pdksh
        bash dash mksh
        zsh ksh
        sh
    )

    local suited=false
    for i in ${shells_array[*]}; do
        if ! [ -z `printf $shell | grep $i` ] && ! $suited; then
            shell=$i
            suited=true
        fi
    done

    echo $shell
}
getshell

Now you can use $(getshell) --version.

This works, though, only on KornShell-like shells (ksh).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
theoden8
  • 773
  • 7
  • 16
  • 3
    "This works, though, only on ksh-like shells." Are you saying I have to verify the shell *before* running this? Hmm... – jpaugh Aug 17 '16 at 20:17
  • @jpaugh, the lists must be supported by the shell sourcing this code, which is not the case for `dash`, `yash` etc. Normally, if you are using `bash`, `zsh`, `ksh`, whatever - you shouldn't care about such things. – theoden8 Aug 18 '16 at 00:50
  • So you're counting bash as "ksh-like"? Got it. That makes more sense – jpaugh Aug 18 '16 at 01:38
  • @jpaugh, well, that's what I meant because `ksh`'s set of features is mostly a subset of `bash`'s features (haven't checked this thoroughly though). – theoden8 Aug 18 '16 at 02:32
1
echo $$ # Gives the Parent Process ID 
ps -ef | grep $$ | awk '{print $8}' # Use the PID to see what the process is.

From How do you know what your current shell is?.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Moisei
  • 1,162
  • 13
  • 30
1

Do the following to know whether your shell is using Dash/Bash.

ls –la /bin/sh:

  • if the result is /bin/sh -> /bin/bash ==> Then your shell is using Bash.

  • if the result is /bin/sh ->/bin/dash ==> Then your shell is using Dash.

If you want to change from Bash to Dash or vice-versa, use the below code:

ln -s /bin/bash /bin/sh (change shell to Bash)

Note: If the above command results in a error saying, /bin/sh already exists, remove the /bin/sh and try again.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Shiva
  • 11
  • 3
1

I like Nahuel Fouilleul's solution particularly, but I had to run the following variant of it on Ubuntu 18.04 (Bionic Beaver) with the built-in Bash shell:

bash -c 'shellPID=$$; ps -ocomm= -q $shellPID'

Without the temporary variable shellPID, e.g. the following:

bash -c 'ps -ocomm= -q $$'

Would just output ps for me. Maybe you aren't all using non-interactive mode, and that makes a difference.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sean
  • 393
  • 2
  • 11
1

Get it with the $SHELL environment variable. A simple sed could remove the path:

echo $SHELL | sed -E 's/^.*\/([aA-zZ]+$)/\1/g'

Output:

bash

It was tested on macOS, Ubuntu, and CentOS.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Junaid
  • 3,477
  • 1
  • 24
  • 24
  • 2
    It specifies which shell to run for programs started by shell, but not necessarily equals shell that is running. I.e. GNU screen won't set itself as `$SHELL` even it is IS user's login "shell". – AnrDaemon Feb 02 '22 at 11:11
0

Grepping PID from the output of "ps" is not needed, because you can read the respective command line for any PID from the /proc directory structure:

echo $(cat /proc/$$/cmdline)

However, that might not be any better than just simply:

echo $0

About running an actually different shell than the name indicates, one idea is to request the version from the shell using the name you got previously:

<some_shell> --version

sh seems to fail with exit code 2 while others give something useful (but I am not able to verify all since I don't have them):

$ sh --version
sh: 0: Illegal option --
echo $?
2
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ajaaskel
  • 1,639
  • 12
  • 12
0

On Mac OS X (and FreeBSD):

ps -p $$ -axco command | sed -n '$p' 
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
zaga
  • 17
  • 1
0

One way is:

ps -p $$ -o exe=

which is IMO better than using -o args or -o comm as suggested in another answer (these may use, e.g., some symbolic link like when /bin/sh points to some specific shell as Dash or Bash).

The above returns the path of the executable, but beware that due to /usr-merge, one might need to check for multiple paths (e.g., /bin/bash and /usr/bin/bash).

Also note that the above is not fully POSIX-compatible (POSIX ps doesn't have exe).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
calestyo
  • 327
  • 2
  • 7
-1

Kindly use the below command:

ps -p $$ | tail -1 | awk '{print $4}'
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ranjithkumar T
  • 1,886
  • 16
  • 21
  • 1
    First one is nonsense, `echo $SHELL` does what you're trying to do and do it well. Second one also isn't good, because `$SHELL` environment variable contains default shell for a current user, not a currently running shell. If I have for example `bash` set as default shell, execute `zsh` and `echo $SHELL`, it'll print `bash`. – David Ferenczy Rogožan Oct 14 '14 at 11:39
  • You are correct Dawid Ferenczy, We can use ps command to determine current shell. [ # ps -p $$ | tail -1 | awk '{print $4}' ]. – Ranjithkumar T Oct 15 '14 at 05:23
  • `echo $SHELL` may be rubbish: `~ $ echo $SHELL /bin/zsh ~ $ bash bash-4.3$ echo $SHELL /bin/zsh bash-4.3$` – SaltwaterC Aug 15 '16 at 10:12
-1

This one works well on Red Hat Linux (RHEL), macOS, BSD and some AIXes:

ps -T $$ | awk 'NR==2{print $NF}' 

alternatively, the following one should also work if pstree is available,

pstree | egrep $$ | awk 'NR==2{print $NF}'
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
-2

And I came up with this:

sed 's/.*SHELL=//; s/[[:upper:]].*//' /proc/$$/environ
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ivan
  • 6,188
  • 1
  • 16
  • 23
-2

You can use echo $SHELL|sed "s/\/bin\///g"

msalihbindak
  • 592
  • 6
  • 21