如何确定我正在工作的当前shell?
我如何确定我正在使用的当前shell?
ps
命令的输出是否足够?
这怎么能在不同的UNIX中完成呢?
-
有三种方法来查找当前shell的可执行文件的名称 :
请注意,如果shell的可执行文件是
/bin/sh
,那么所有这三种方法都可能被愚弄,但实际上它是一个重命名的bash
(经常发生)。因此,你的第二个问题是
ps
输出是否会被“ 不总是 ”回答。-
echo $0
– 将打印程序名称…在shell的情况下是实际的shell -
ps -ef | grep $$ | grep -v grep
ps -ef | grep $$ | grep -v grep
– 这将在正在运行的进程列表中查找当前的进程ID。 由于当前进程是shell,因此它将被包含在内。这不是100%可靠的,因为你可能有其他进程的
ps
列表中包含与shell的进程ID相同的编号,特别是如果该编号是小号(例如,如果shell的PID是“5”,你可能会发现名为“java5 “或”perl5“在相同的grep
输出!)。 这是“ps”方法的第二个问题,除了不能依赖shell的名字之外。 -
echo $SHELL
– 当前shell的path被存储为任何shell的SHELL
variables。 需要注意的是,如果你明确地启动一个shell作为一个subprocess(例如,它不是你的loginshell),你将会得到你的loginshell的值。 如果这是可能的话,请使用ps
或$0
方法。
-
-
但是,如果可执行文件与实际的shell不匹配(例如
/bin/sh
实际上是bash或ksh),则需要启发式。 以下是一些特定于各种shell的环境variables:-
$version
在tcsh上设置 -
$BASH
在bash上设置 -
$shell
(小写)在csh或tcsh中设置为实际的shell名称 -
$ZSH_NAME
在zsh上设置 -
ksh有
$PS3
和$PS4
设置,而普通的Bourne shell(sh
)只有$PS1
和$PS2
设置。 这通常看起来最难分辨 – 我们已经在Solaris$FCEDIT
上安装的sh
和ksh
之间的整套环境variables的唯一区别是$ERRNO
,$FCEDIT
,$LINENO
,$PPID
,$PS3
,$PS4
,$RANDOM
,$SECONDS
,$TMOUT
。
-
ps -p $$
应该在包含ps -ef
和grep
的解决scheme(在支持ps
POSIX选项的任何Unix变体上)的任何地方工作,并且将不会受到通过对可能出现在其他地方的数字序列进行grepping引入的误报的影响。
尝试
ps -p $$ -oargs=
要么
ps -p $$ -ocomm=
你可以试试:
ps | grep `echo $$` | awk '{ print $4 }'
要么:
echo $SHELL
如果你只是想确保用户正在用bash调用脚本:
if [ ! -n "$BASH" ] ;then echo Please run this script $0 with bash; exit 1; fi
$SHELL
不一定总是显示当前的shell。 它只反映了被调用的默认shell。
为了testing上面的内容,说bash
是默认的shell,试着echo $SHELL
,然后在同一个terminal上进入一些其他的shell(例如ksh)并且尝试$SHELL
,在这两种情况下你都会看到bash的结果。
要获取当前shell的名称,请使用cat /proc/$$/cmdline
并通过readlink /proc/$$/exe
shell可执行文件的path
ps是最可靠的方法。 shellenvar不保证被设置,即使它,它可以很容易被欺骗
我有一个简单的技巧来find当前的shell。 只要input一个随机string(这不是一个命令)。 它会失败,并返回一个“未find”的错误,但在行首会说出它是哪个shell:
ksh: aaaaa: not found [No such file or directory] bash: aaaaa: command not found
这会给总是实际使用的shell – 获取真正的可执行文件的名称,而不是shell名称(即ksh93
而不是ksh
等) ksh93
/bin/sh
将显示实际使用的shell:
ls -l /proc/$$/exe | sed 's%.*/%%'
我知道在这里有很多人说ls
输出应该是新的处理,但是你有一个shell使用特殊字符命名的概率或者放在一个用特殊字符命名的目录中的概率是多less? 如果仍是这样,这里有很多其他的例子做不同的事情。
我打印父进程的变种。
ps -p $$ | awk '$1 == PP {print $4}' PP=$$
为什么运行不必要的应用程序,当'awk'可以为你做?
假设你的/bin/sh
支持POSIX标准,并且你的系统已经安装了lsof
命令 – 在这种情况下, lsof
一个可能替代scheme可能是pid2path
– 你也可以使用(或改编)以下脚本来打印完整path:
#!/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}'
我已经尝试了很多不同的方法,对我来说最好的是:
ps -p $$
它也在Cygwin下工作,不能产生误报作为PID grepping。 有了一些清理,它只输出一个可执行文件名(在Cygwin中带path):
ps -p $$ | tail -1 | awk '{print $NF}'
你可以创build一个函数,所以你不必记住它:
# print currently active shell shell () { ps -p $$ | tail -1 | awk '{print $NF}' }
…然后执行shell
。
在Debian和Cygwin下testing。
echo $$ # Gives the Parent Process ID ps -ef | grep $$ | awk '{print $8}' #use the PID to see what the process is.
在Mac OS X(&FreeBSD)上:
ps -p $$ -axco command | sed -n '$p'
如果你只是想检查你正在运行(特定版本的)Bash,最好的办法是使用$BASH_VERSINFO
数组variables。 作为一个(只读的)数组variables,它不能在环境中设置,所以你可以确定它是来自当前shell(如果有的话)。 但是,由于Bash在调用sh
时具有不同的行为,因此还需要检查$BASH
环境variables以/bash
结尾。
在一个脚本中,我使用的函数名称是-
(不是下划线),依赖于关联数组(在Bash 4中添加),我有以下的理智检查(有用户错误信息):
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
你可以省略第一种情况下对function的偏执性function检查,并假设将来的bash版本是兼容的。
从“ps”的输出中清除PID是不需要的,因为您可以从/ proc目录结构中读取任何PID的相应命令行:
echo $(cat /proc/$$/cmdline)
然而,这可能不仅仅是简单的:
echo $0
关于运行实际上与名称不同的shell指示,一个想法是使用您之前获得的名称从shell请求版本:
<some_shell> --version
嘘似乎失败与退出代码2,而其他人给了一些有用的东西(但我无法validation所有,因为我没有他们):
$ sh --version sh: 0: Illegal option -- echo $? 2
没有任何答案与鱼壳(它没有variables$$
或$0
)。
这适用于我(在sh
, bash
, fish
, ksh
, csh
, true
, tcsh
和zsh
; openSUSE 13.2):
ps | tail -n 4 | sed -E '2,$d;s/.* (.*)/\1/'
这个命令输出string像bash
。 我在这里只用了ps
, tail
和sed
(没有GNU extesions,试着添加--posix
来检查它)。 他们都是标准的POSIX命令。 我确定tail
可以被删除,但是我的sed
不够强壮。
在我看来,这个解决scheme是不是很便携,因为它不适用于OS X. 🙁
这不是很干净的解决scheme,但做你想要的。
我意识到,这个2015年的老年人的答案有点迟,但…
#MUST BE SOURCED.. getshell() { local shell="`ps -p $$ | tail -1 | awk '{print $4}'`" shells_array=( # It is important that the shells are listed by the decrease of their length name. 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
现在你可以使用$(getshell) --version.
但是,这只适用于类似ksh的炮弹。
请使用下面的命令:
# ps -p $$ | tail -1 | awk '{print $4}'
我的解决scheme
ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1
这应该是跨不同的平台和shell的便携式。 它像其他解决scheme一样使用ps
,但是它不依赖于sed
或awk
并且从pipe道和ps
本身过滤出垃圾,因此shell始终应该是最后一个入口。 这样我们就不需要依赖不可移植的PIDvariables或者挑出正确的行和列。
我已经用bash,zsh和fish在Debian和MacOS上进行了testing(对于大多数这些解决scheme,如果不更改专门用于鱼的expression式,因为它使用了不同的PIDvariables,则不适用于这些解决scheme)。
有很多方法可以findshell及其相应的版本。 这里有几个为我工作。
直向前
- $> echo $ 0 (给你程序名,在我的情况下输出是-bash )
- $> $ SHELL (这会把你带到shell中,并在提示符下获得shell的名字和版本,在我的例子中是bash3.2 $ )
- $> echo $ SHELL (这会给你可执行的path,在我的情况下/ bin / bash )
- $> $ SHELL –version (这将提供有关使用许可证types的shell软件的完整信息)
黑客的做法
$> *******(键入一组随机字符,并在输出中获得shell名称。在我的情况下, -bash:chapter2-a-sample-isomorphic-app:command not found )