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).
echo $$ # Gives the Parent Process ID
ps -ef | grep $$ | awk '{print $8}' # Use the PID to see what the process is.
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.
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. :(
You can try:
ps | grep `echo $$` | awk '{ print $4 }'
Or:
echo $SHELL
On Mac OS X (and FreeBSD):
ps -p $$ -axco command | sed -n '$p'
$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
.
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.
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)
If you just want to ensure the user is invoking a script with Bash:
if [ ! -n "$BASH" ] ;then echo Please run this script $0 with bash; exit 1; fi
There are many ways to find out the shell and its corresponding version. Here are few which worked for me.
Straightforward
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)
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).
Try
ps -p $$ -oargs=
or
ps -p $$ -ocomm=
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.
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
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}'
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.
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}'
And i came up with this
sed 's/.*SHELL=//; s/[[:upper:]].*//' /proc/$$/environ
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.
Kindly use the below command:
ps -p $$ | tail -1 | awk '{print $4}'
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
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.
Source: Stackoverflow.com