As per my knowledge, to determine the current shell we use echo $0 in the shell. Rather I want my script to check in which shell it is running. So, I tried to print $0 in the script and it returns the name of the script as it should. So, my question is how can I find which shell is my script running in during runtime?
- 320,670
- 36
- 633
- 936
- 1,724
- 8
- 27
- 34
-
what scripting language are you using? Also, worse case, you can always shell out a system command to get the "echo $0" results inside of the script. – BriGuy Apr 04 '13 at 05:45
-
`echo $0` is not an option here ,as the script will run on many different machines where first thing I'll need to check is the shell. – g4ur4v Apr 04 '13 at 05:55
-
So what is the scripting language then? – BriGuy Apr 04 '13 at 05:58
-
@BriGuy: It's a unix shell script. – g4ur4v Apr 04 '13 at 06:01
-
4Well, if you add `#! /bin/sh -` at the top, it will run in `sh`. Do you mean _what variant of `sh` is it?_ – Stéphane Chazelas Apr 04 '13 at 06:58
-
Check the value of `$SHELL`. – ott-- Apr 12 '13 at 22:51
-
This is similar to: [How to test what shell I am using in a terminal?](http://unix.stackexchange.com/questions/9501/how-to-test-what-shell-i-am-using-in-a-terminal) Perhaps not a dup since this question is specifically about being within a script. But I think that's the implied context for the other question, because it shouldn't be too hard for a user to know which shell they're running interactively, should it? – depquid Apr 16 '13 at 20:35
-
@g4ur4v What do you mean by "using ksh shell script"? If you know you're using ksh, what are you trying to determine? – depquid Apr 18 '13 at 15:42
-
ksh is the shell where I am developing the script...Its not the shell where I might run it. – g4ur4v Apr 19 '13 at 21:37
-
Is not this a duplicate of [How to test what shell I am using in a terminal?](https://unix.stackexchange.com/questions/9501/how-to-test-what-shell-i-am-using-in-a-terminal)? – rugk Sep 19 '17 at 23:17
8 Answers
Maybe not what you're asking for, but this should work to some extent to identify the interpreter currently interpreting it for a few like
- Thompson shell (
osh), - Bourne shell,
- Bourne-again shell (
bash), - Korn shell (
ksh88,ksh93,pdksh,mksh), zsh,- Policy-compliant Ordinary shell (
posh), - Yet Another shell (
yash), rcshell,akangashell,- es shell,
wishTCL interpreter,tclshTCL interpreter,expectTCL interpreter,- Perl,
- Python,
- Ruby,
- PHP,
- JavaScript (nodejs, SpiderMonkey shell and JSPL at least)
- MS/Wine
cmd.exe,command.com(MSDOS, FreeDOS...).
'echo' +"'[{<?php echo chr(13)?>php <?php echo PHP_VERSION.chr(10);exit;?>}\
@GOTO DOS [exit[set 1 [[set 2 package] names];set 3 Tcl\ [info patchlevel];\
if {[lsearch -exact $1 Expect]>=0} {puts expect\ [$2 require Expect]\ ($3)} \
elseif {[lsearch -exact $1 Tk]>=0} {puts wish\ ($3,\ Tk\ [$2 require Tk])} \
else {puts $3}]]]' >/dev/null ' {\">/dev/null \
">"/dev/null" +"\'";q="#{",1//2,"}";a=+1;q='''=.q,';q=%{\"
'echo' /*>/dev/null
echo ">/dev/null;status=0;@ {status=1};*=(" '$' ");~ $status 1&&{e='"\
"';eval catch $2 ^'&version {eval ''echo <='^ $2 ^'&version''}';exit};e='"\
"';if (eval '{let ''a^~a''} >[2] /dev/null'){e='"\
"';exec echo akanga};eval exec echo rc $2 ^ version;\" > /dev/null
: #;echo possibly pre-Bourne UNIX V1-6 shell;exit
if (! $?version) set version=csh;exec echo $version
:DOS
@CLS
@IF NOT "%DOSEMU_VERSION%"=="" ECHO DOSEMU %DOSEMU_VERSION%
@ECHO %OS% %COMSPEC%
@VER
@GOTO FIN
", unless eval 'printf "perl %vd\n",$^V;exit;'> "/dev/null";eval ': "\'';
=S"';f=false e=exec\ echo n=/dev/null v=SH_VERSION;`(eval "f() { echo :
};f")2>$n` $f||$e Bourne-like shell without function
case `(: ${_z_?1}) 2>&1` in 1) $e ash/BSD sh;;esac;t(){
eval "\${$1$v+:} $f &&exec echo ${2}sh \$$1$v";};t BA ba;t Z z;t PO po;t YA ya
case `(typeset -Z2 b=0;$e $b)2>$n` in 00) (eval ':${.}')2>$n&&eval '
$e ksh93 ${.sh.version}';t K pdk;$e ksh88;;esac;case `(eval '$e ${f#*s}$($e 1
)$((1+1))')2>$n` in e12)$e POSIX shell;;esac;$e Bourne-like shell;: }
print "ruby ",RUBY_VERSION,"\n";exit;' ''';import sys
print("python "+sys.version);z='''*/;
s="";j="JavaScript";if(typeof process=="object"){p=console.log;p(process.title
,process.version)}else{p=print;p((f="function")==(t=typeof version)?"string"==
typeof(v=version())?v:(typeof build!=f?"":s= "SpiderMonkey ")+j+" "+v:(t==
"undefined"?j+"?":version)+"\n");if(s)build()}/*
:FIN } *///'''
I posted the initial version of that which_interpreter script circa 2004 on usenet. Sven Mascheck has a (probably more useful to you) script called whatshell that focuses on identifying Bourne-like shells. You can also find a merged version of our two scripts there.
- 522,931
- 91
- 1,010
- 1,501
-
3This cannot identify Python 3, only Python 2. To fix that, change `print` to be a function. – Chris Down Apr 04 '13 at 09:19
-
53This is the biggest WTF moment of the year so far. +1 for taking portability past sanity. – l0b0 Apr 04 '13 at 11:35
-
4
-
2@xfix, I remember trying even before adding php and javascript but couldn't find a solution then. The complexity grows exponentially with the number of languages to support (as everything you add must be valid (or at least have unnoticeable side-effects) in all the supported languages) so it would be even more difficult now. I'm not saying it's impossible but that would probably mean dropping support for some other languages. – Stéphane Chazelas Mar 23 '14 at 20:45
-
This is extremely interesting and impressive, but it identifies `zsh` on my system as `bash 3.2.53(1)-release`. – iconoclast Aug 09 '15 at 20:00
-
2@iconoclast, you mean you ran `zsh ./that-script` and it returned `bash 3.2.53(1)-release`? More likely you ran it as `./that-script` from within `zsh` which got it interpreted by your `sh`, and your `sh` happens to be `bash`. – Stéphane Chazelas Aug 09 '15 at 20:37
-
Yes, the latter: from an interactive `zsh` session I ran `whatshell.sh`. – iconoclast Aug 09 '15 at 21:22
-
4@iconoclast, so it correctly identifies `bash 3.2.53(1)-release` as the interpreter interpreting it. – Stéphane Chazelas Aug 10 '15 at 08:53
On linux you can use /proc/PID/exe.
Example:
# readlink /proc/$$/exe
/bin/zsh
- 70,657
- 19
- 188
- 223
-
3That's a bit too specific for me (e.g. on Debian it prints zsh4 or ksh93). `/bin/sed -r -e 's/\x0.*//' /proc/$$/cmdline` gives zsh or ksh instead. (That'd be $0 if shells didn't magically fix this to give the scripts name instead). – frostschutz Apr 12 '13 at 23:17
-
-
Not really. It depends on what the OP really wants. Not reading the link also causes `#!/bin/sh` to return just `sh` even if it's really bash, dash, etc. Can't follow links and not follow links at the same time. Unless you check if it's `sh` and follow then or something, but that solution is plain weird. – frostschutz Apr 14 '13 at 17:00
-
5This suffers from the dreaded *All the world's a Linux box* disease. `/proc` is as ugly and unportable as it gets. – Jens Apr 15 '13 at 12:58
-
Originally thought of this one as well. See my answer for an OS agnostic solution. :) Despite the Linux Box Disease, /proc continues to be a great way to access process info. – Wing Tang Wong Apr 16 '13 at 00:24
-
9@Jens that's why I specified this applies to Linux only. `/proc` is not 'ugly'. `/proc` is often a very elegant solution. Unportable yes, but because something is unportable doesn't make it ugly. – phemmer Apr 16 '13 at 12:17
-
3@Patrick I consider `/proc` ugly because the files in it may come and go at the whim of developers and the contents of files is prone to change without notice, causing endless pain due to bitrot and moving target file formats. – Jens Apr 18 '13 at 11:12
-
@frostschutz’s answer doesn’t seem to be portable (doesn’t work with BSD `sed`). – Diti Feb 06 '20 at 18:39
-
`/proc` does not change at the whim of developers. `/proc` contents are relied upon by tons of tools, such as `top`, `ps`, `sar`, `ss`, and hundreds/thousands of others. If it changed on a whim, you'd have a few million irritated users & developers. – phemmer Jun 30 '21 at 12:35
This is what I use in my .profile to check for various shells on the systems I work on. It doesn't make fine distinctions between ksh88 and ksh93, but it has never failed me.
Note that it doesn't require a single fork or pipe.
# 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
- 1,738
- 4
- 17
- 36
-
1Note that only very recent versions of `ksh93` have `$KSH_VERSION`. That variable comes from `pdksh` and never made it to AT&T ksh88. – Stéphane Chazelas Apr 15 '13 at 21:28
-
-
2Right. Note that `posh` (pdksh with most non-POSIX features removed so you would probably want to call it "sh") has no FCEDIT nor KSH_VERSION but has PS3 (maybe not for long), though it's unlikely for one to have it as a login shell. Also note that the code above wouldn't reflect whether `bash` or `zsh` are in `sh` emulation mode, which may be a problem if you're using `$PROFILE_SHELL` to decide whether or not to enable this or that feature. See also [Sven Mascheck's whatshell](http://www.in-ulm.de/~mascheck/various/whatshell/) for more you may (or may not) want to check. – Stéphane Chazelas Apr 16 '13 at 06:25
-
1
You could try
ps -o args= -p "$$"
which will give you the name of the command associated with the script's pid.
- 522,931
- 91
- 1,010
- 1,501
- 8,017
- 2
- 33
- 50
-
Doesn't work when using a shebang as far as I can tell. http://sprunge.us/QeHD – Chris Down Apr 04 '13 at 09:20
-
Sorry, @ChrisDown, Flup. My bad, I had incorrectly translated `cmd` to `comm` when POSIXifying the answer. – Stéphane Chazelas Apr 04 '13 at 11:04
Portable solution (tested in linux and macOS):
ps -o args= -p $$ | egrep -m 1 -o '\w{0,5}sh'
where:
"ps -o args=" retrieves the command line arguments
"$$" gives you the current PID
"-m 1" to finish searching after the first match
"-o" to only display matching portion
"\w{0,5}sh" regular expression to find things like bash in /bin/bash or ksh in -ksh or sh in sh (Maximum 5 characters+sh)
hope it helps
- 21
- 1
-
`egrep` is not universal. `grep -E` would be more "portable", but still non-standard. The `\w` thing is a GNU-ism supported by some `grep` implementation. This returns `sh` when I'm in `zsh` on OpenBSD if I run it as-is (probably because `\w` is only matching a literal `w`). – Kusalananda Jan 03 '20 at 15:17
If there is the lsof command available on your system, you can get the full path of the parent shell executable by getting the parent PID via ps and parsing the ouput of lsof -p $ppid (see How to determine the current shell i'm working on?).
#!/bin/sh
ppid="`ps -p "$$" -o ppid=`"
lsof -nP -p "$ppid" | awk 'NR==3 {print $NF; exit}'
-
On my system this returns `/`, if I use `NR==4` I get the path to the shells parent. – Thor Apr 15 '13 at 07:10
-
1Note that POSIX `sh`s have the `$PPID` variable. On `Linux`, you can use `readlink -f "/proc/$PPID/exe"`. – Stéphane Chazelas Sep 09 '14 at 12:48
-
Please, stop using backticks in shell scripts. It's rarely the right tool for the job. – Tripp Kinetics Jan 13 '23 at 22:17
Outside of Linux land or lacking access to the /proc filesystem or equivelent, you can make use of pstree:
Assuming you have the pid of
On a Mac:
./test.sh
16012
-+= 00001 root /sbin/launchd
\-+= 00245 wingwong /sbin/launchd
\-+= 04670 wingwong /Applications/Utilities/Terminal.app/Contents/MacOS/Terminal -psn_0_2052597
\-+= 11816 root login -pf wingwong
\-+= 11817 wingwong -bash
\-+= 16012 wingwong ksh ./test.sh
\-+- 16013 wingwong pstree -p 16012
On a Linux box:
./test.sh
14981
bash(14981)---pstree(14982)
The format and style of the output from pstree differs, depending on your environment, but you can enforce ASCII output and then sed/tr/awk/etc. filter the output to get the shell that is running the script.
So a cleaned up output version(works for Mac or Linux OS runs):
#!/usr/bin/env sh
pstree -p $$ | tr ' ()' '\012\012\012' | grep -i "sh$" | grep -v "$0" | tail -1
On run yields:
./test.sh
sh
And when run with a different shell:
#!/usr/bin/env ksh
pstree -p $$ | tr ' ()' '\012\012\012' | grep -i "sh$" | grep -v "$0" | tail -1
Yields:
./test.sh
ksh
No root or special filesystem required. Note, my filtering assumes that the shell binary name ends with sh and that there are no intermediate entries which end with sh. Also assumes that you didn't name your script "sh" or some unfortunate grep pattern that will obliterate information. :) Will require some customization for your own environment to ensure a higher degree of foolproofing.
- 326
- 1
- 5
You can use the command:
$ echo $SHELL
to find out the shell from within the script.
- 9,859
- 12
- 51
- 59
-
23No. `$SHELL` is the shell of choice of the user. Initialised from the login shell of the user. Nothing to do with the currently running shell. – Stéphane Chazelas Apr 04 '13 at 06:55