How to determine the current shell I'm working on?
如何确定当前正在处理的shell?
单是
如何在不同风格的Unix中实现这一点?
查找当前shell可执行文件的名称有三种方法:
请注意,如果shell的可执行文件是
/bin/sh ,所有3种方法都会被愚弄,但它实际上是一个重命名的bash ,例如(这种情况经常发生)。因此,关于
ps 输出是否可行的第二个问题的答案是"不总是"。echo $0 将打印程序名…在壳的情况下,它是实际的壳ps -ef | grep $$ | grep -v grep —这将在正在运行的进程列表中查找当前进程ID。由于当前进程是shell,因此将包括它。这不是100%可靠的,因为您可能有其他进程,它们的
ps 列表包含与shell进程ID相同的数字,特别是如果该ID是一个小的(例如,如果shell的PID是"5",您可以在同一grep 输出中找到名为"java5"或"perl5"的进程!)这是"ps"方法的第二个问题,除了不能依赖shell名称。echo $SHELL —当前shell的路径存储为任何shell的SHELL 变量。对于这个问题,需要注意的是,如果将shell显式地作为子进程(例如,它不是您的登录shell)启动,那么您将获得登录shell的值。如果可能的话,使用ps 或$0 方法。但是,如果可执行文件与实际shell不匹配(例如,
/bin/sh 实际上是bash或ksh),则需要启发式方法。以下是特定于各种外壳的一些环境变量:TCSH上设置了
$version 。$BASH 设置在bash上在csh或tcsh中将EDOCX1(小写)设置为实际shell名称
在zsh上设置
$ZSH_NAME 。ksh有
$PS3 和$PS4 套,而普通bourne shell(sh 套)只有$PS1 和$PS2 套。这似乎是最难区分的——我们在Solaris Boxen上安装的sh 和ksh 的整个环境变量集合的唯一区别是$ERRNO 、$FCEDIT 、$LINENO 、$PPID 、$PS3 、$PS4 、$RANDOM 、$SECONDS 、$TMOUT 。
应适用于涉及
尝试
1 | ps -p $$ -oargs= |
或
1 | ps -p $$ -ocomm= |
如果您只想确保用户使用bash调用脚本:
1 | if [ ! -n"$BASH" ] ;then echo Please run this script $0 with bash; exit 1; fi |
你可以试试:
1 | ps | grep `echo $$` | awk '{ print $4 }' |
或:
1 | echo $SHELL |
要测试以上内容,假设
要获取当前shell的名称,请使用
PS是最可靠的方法。不能保证设置shell envar,即使设置了shell envar,也很容易被欺骗。
我有一个简单的技巧来找到当前的外壳。只需键入一个随机字符串(它不是命令)。它将失败并返回一个"未找到"错误,但在行首它将指出它是哪个shell:
1 2 | ksh: aaaaa: not found [No such file or directory] bash: aaaaa: command not found |
这将始终给出实际使用的shell—获取实际可执行文件的名称,而不是用于
1 | ls -l /proc/$$/exe | sed 's%.*/%%' |
我知道这里有很多人说
我的变体打印父进程。
1 | ps -p $$ | awk '$1 == PP {print $4}' PP=$$ |
为什么运行不必要的应用程序,而"awk"可以为您做到这一点?
我尝试过许多不同的方法,对我来说最好的方法是:
它也在Cygwin下工作,不能产生误报,因为PID变灰。通过一些清理,它只输出一个可执行文件名(在cygwin with path下):
1 | ps -p $$ | tail -1 | awk '{print $NF}' |
您可以创建一个函数,这样就不必记住它:
1 2 3 4 | # print currently active shell shell () { ps -p $$ | tail -1 | awk '{print $NF}' } |
…然后执行
在Debian和Cygwin下测试。
如果您的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #!/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 ""lsof failed""try: sudo lsof -p \`ps -p \$\$ -o ppid=\`"; exit 1; } printf"%s ""${lsofstr}" | LC_ALL=C awk -v var="${awkstr}" '$NF ~ var {print $NF}' |
1 2 | echo $$ # Gives the Parent Process ID ps -ef | grep $$ | awk '{print $8}' #use the PID to see what the process is. |
来自http://www.unix.com/unix-dummies-questions-answers/10390-how-do-you-know-what-your-current-shell.html
在Mac OS X上(&;freebsd):
1 | ps -p $$ -axco command | sed -n '$p' |
如果您只想检查是否正在运行(特定版本的)bash,最好的方法是使用
在我编写的一个脚本中,它使用了带有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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 |
在第一种情况下,您可以省略对特性的一些偏执的功能检查,假设未来的bash版本是兼容的。
你要知道,无论你是使用破折号,壳/ bash。
1)LS–la /bin/sh,如果result is /bin/sh > /bin/bash==>然后你使用bash shell是。
如果result is /bin/sh>//==>则是仪表的壳体是用破折号。
如果你想更改到Dash Bash或反之亦然,使用下面的代码LN S /bin/bash /bin/sh(改变一个bash shell)
注:如果上面的命令结果的误差在A说,/bin/sh已经存在,删除"/bin/sh和再试一次。
没有一个答案适用于
这对我来说是可行的(在
1 | ps | tail -n 4 | sed -E '2,$d;s/.* (.*)/\1/' |
这个命令输出类似于
在我看来,这个解决方案不是非常可移植的,因为它在OS X上不起作用。(
不需要从"ps"的输出中提取pid,因为您可以从/proc目录结构中读取任何pid的相应命令行:
1 | echo $(cat /proc/$$/cmdline) |
然而,这可能并不比简单地:
1 | echo $0 |
关于运行实际不同于名称所指示的shell,一个想法是使用以前获得的名称从shell请求版本:
1 | <some_shell> --version |
sh似乎失败了,退出代码为2,而其他人给出了一些有用的东西(但我无法验证所有的东西,因为我没有它们):
1 2 3 4 | $ sh --version sh: 0: Illegal option -- echo $? 2 |
这不是很干净的解决方案,但可以满足您的需要。
我知道答案在这个美好的2015年有点晚了,但是…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #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 |
现在你可以使用
不过,这种方法只适用于像ksh这样的外壳。
我的解决方案:
1 | ps -o command | grep -v -e"\<ps\>" -e grep -e tail | tail -1 |
这应该是在不同的平台和便携式外壳。它使用
我已经测试了在Debian和MacOS和bash和鱼(zsh),它不适合与大多数研究没有具体的解决方案,因为它表达的鱼,使用不同的控制变量)。
有许多的方式找出壳和其相应的版本。这里是一个为我工作的。
直向前
hackish方法
美元* * * * * * *(A型随机字符集和输出你想要得到的壳的名字。在我的案例:一chapter2 bash命令示例应用程序不存在同构):
请使用以下命令:
1 | # ps -p $$ | tail -1 | awk '{print $4}' |
这一作品也在RHEL,MacOS,BSD和一些aixes
1 | ps -T $$ | awk 'NR==2{print $NF}' |
也因此,如果pstree以下工作应该是可用的,
1 | pstree | egrep $$ | awk 'NR==2{print $NF}' |