如何确定我正在使用的当前shell?

jos*_*osh 587 unix bash shell csh tcsh

如何确定我正在使用的当前shell?

ps仅仅命令的输出是否足够?

如何在不同版本的UNIX中完成?

DVK*_*DVK 742

  • 有3种方法可以找到当前shell的可执行文件的名称:

    请注意,如果shell的可执行文件是,/bin/sh但它实际上是重命名的bash(经常发生),所有3种方法都可能被欺骗.

    因此,关于ps输出是否会做的第二个问题是" 并非总是 ".

    1. echo $0 - 将打印程序名称...在shell的情况下是实际的shell

    2. ps -ef | grep $$ | grep -v grep - 这将在正在运行的进程列表中查找当前进程ID.由于当前进程是shell,因此将包含它.

      这不是100%可靠,因为您可能有其他进程,其ps列表包含与shell的进程ID相同的编号,特别是如果该ID是一个小#(例如,如果shell的PID为"5",您可能会发现名为"java5"的进程或"perl5"在同一grep输出!).这是"ps"方法的第二个问题,除了不能依赖shell名称.

    3. echo $SHELL- 当前shell的路径存储SHELL为任何shell 的变量.这个问题的警告是,如果你明确地将shell作为子进程启动(例如它不是你的登录shell),你将获得你的登录shell的值.如果可能,请使用ps$0方法.


  • 但是,如果可执行文件与您的实际shell不匹配(例如/bin/sh实际上是bash或ksh),则需要启发式方法.以下是一些特定于各种shell的环境变量:

    • $version 在tcsh上设置

    • $BASH 在bash上设置

    • $shell (小写)设置为csh或tcsh中的实际shell名称

    • $ZSH_NAME 在zsh上设置

    • ksh有$PS3$PS4设置,而普通的Bourne shell(sh)只有$PS1$PS2设置.这通常似乎是最难区分-在整组伴有环境之间的变量的唯一的区别shksh我们已经安装在Solaris上Boxen有是$ERRNO,$FCEDIT,$LINENO,$PPID,$PS3,$PS4,$RANDOM,$SECONDS,$TMOUT.

  • `ps -p $$`作为[Matthew Slattery](http://stackoverflow.com/questions/3327013/how-to-determine-the-current-shell-im-working-on/3327108#3327108)指出.对于`ksh`:`echo $ KSH_VERSION`或`echo $ {.sh.version}`. (13认同)
  • _"`ps -ef | grep ...`...这不是100%可靠的......"_通过`egrep`或`grep -e`使用一个简单的正则表达式可以很容易地将可靠性带到100%的所有意图和目的:`ps -ef | egrep"^\s*\d +\s + $$\s +"`.`^`确保我们从行的开头开始,`\ d +`吃掉UID,`$$`匹配PID,`\ s*`和`\ s +`帐号并确保其他部分之间的空白. (3认同)
  • echo $ SHELL做到了!谢谢。:-) (2认同)
  • @ SlippD.Thompson在GNU/Linux中不起作用.但这似乎有用:`ps -ef | awk'$ 2 == pid'pid = $$` (2认同)

Mat*_*ery 90

ps -p $$

应该在解决方案涉及ps -efgrep执行的任何地方工作(在任何支持POSIX选项的ps Unix变体上),并且不会遭受grepping为可能出现在其他地方的数字序列引入的误报.

  • 有些shell有自己的内置版本的`ps`,可能不理解`-p`,所以你可能需要使用`/ bin/ps -p $$`. (11认同)
  • 我熟悉的所有shell都理解`$$`除了'fish`,你必须使用`ps -p%self`. (11认同)
  • 实际上,你不应该依赖诸如`/ bin/ps`之类的硬路径.`ps`很容易(实际上现在很常见)安装在`/ usr/bin`中.`$(ps)-p $$`是一种更好的方法.当然,这不适用于鱼类,也可能是其他一些贝壳.我认为这是鱼的"(ps ps)-p%self". (2认同)
  • 在一些最小的系统中,比如 debian-slim docker 容器, ps 可能不存在。在这种情况下,这种方法仍然有效:`readlink /proc/$$/exe` (2认同)

Nah*_*eul 38

尝试

ps -p $$ -oargs=
Run Code Online (Sandbox Code Playgroud)

要么

ps -p $$ -ocomm=
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的短期.我正在使用自己的`ps -o fname --no-headers $$`. (3认同)
  • 我发现,如果您在子 shell 中执行此操作,那么通过匹配父级的 PID 以及实际的 shell 进程,可能会导致虚假的额外行。为此,我使用 `-q` 而不是 `-p`:`SHELL=$(ps -ocomm= -q $$)` (2认同)

Pet*_*erg 29

如果您只是想确保用户使用bash调用脚本:

if [ ! -n "$BASH" ] ;then echo Please run this script $0 with bash; exit 1; fi
Run Code Online (Sandbox Code Playgroud)

  • 它不应该更接近顶部,因为它根本不回答问题.如果问题是"如何检查脚本是否在bash下运行",我投票支持它. (2认同)
  • @DawidFerenczy - 这个问题是你搜索那个短语时的最佳结果.从长远来看,我认为答案回答人们正在寻找的内容而不是回答原始问题的内容更为重要. (2认同)
  • 另外,如果从bash调用tcsh,则在tcsh下定义变量$ BASH _is_ (2认同)

kar*_*lip 19

你可以试试:

ps | grep `echo $$` | awk '{ print $4 }'
Run Code Online (Sandbox Code Playgroud)

要么:

echo $SHELL
Run Code Online (Sandbox Code Playgroud)

  • 什么是`\`echo $$ \``的意思,当简单的`$$`会做什么? (9认同)
  • 当`/ pattern/{action}`会这样做时,awk后跟awk有什么意义呢? (6认同)
  • `$ SHELL`环境变量包含一个shell,它被配置为当前用户的默认值.它不反映当前正在运行的shell.由于误报,最好使用`ps -p $$`而不是grepping $$. (4认同)

sr0*_*853 11

$SHELL不必总是显示当前的shell.它仅反映要调用的默认shell.

为了测试上面的内容,Say bash是默认shell,尝试echo $SHELL,然后在同一个终端中,进入其他shell(例如ksh)并尝试$SHELL,在两种情况下你都会看到结果为bash.

要获取当前shell的名称,请使用cat /proc/$$/cmdline和执行shell可执行文件的路径readlink /proc/$$/exe

  • ...只要你有`/ proc`. (5认同)

enn*_*ler 9

ps是最可靠的方法.SHELL envar不保证设置,即使它是,它可以很容易欺骗

  • +1 $ SHELL是需要生成一个的程序的默认shell.它不一定反映当前正在运行的shell. (11认同)

小智 8

我有一个简单的技巧来找到当前的shell.只需键入随机字符串(不是命令).它会失败并返回一个"未找到"的错误,但是在行的开头它将说明它是哪个shell:

ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found
Run Code Online (Sandbox Code Playgroud)

  • 不擅长剧本。`echo 'aaaa' > 脚本;chmod +x 脚本;./script` 给出 `./script.sh: 1: aaaa: not found` (5认同)

vad*_*bog 7

这将始终给出实际使用的shell - 获取实际可执行文件的名称而不是shell名称(即ksh93代替ksh等等)For For /bin/sh将显示使用的实际shell:iedash

ls -l /proc/$$/exe | sed 's%.*/%%'
Run Code Online (Sandbox Code Playgroud)

我知道有很多人说ls输出应该是新处理的,但是你有一个使用特殊字符命名的shell或放在一个用特殊字符命名的目录中的概率是多少?如果仍然是这种情况,这里还有很多其他的例子.

  • 如果你*在Linux上,我们更喜欢`basename $(readlink/proc/$$/exe)`到`ls` +`sed` +`echo`. (4认同)
  • 这只是在没有提供`/ proc`的所有Unices上的错误.并非所有的世界都是Linux机器. (2认同)
  • 这将给出实际的*可执行文件*的名称,而不是实际的*shell*。当实际的 shell 作为 busybox 小程序链接时,说“ash -> /bin/busybox”,这将给出 /bin/busybox。 (2认同)

Dev*_*wal 7

有很多方法可以找出shell及其对应的版本。这里有几个对我有用。

直截了当

  1. $> echo $0(给你程序名称。在我的例子中,输出是-bash。)
  2. $> $SHELL(这将带您进入 shell,并在提示中获得 shell 名称和版本。在我的情况下是bash3.2$。)
  3. $> echo $SHELL(这将为您提供可执行路径。在我的情况下/bin/bash。)
  4. $> $SHELL --version(这将提供有关具有许可证类型的外壳软件的完整信息)

黑客方法

$> ******* (输入一组随机字符,在输出中你会得到 shell 名称。在我的例子中-bash:chapter2-a-sample-isomorphic-app: command not found


小智 5

如果您/bin/sh支持 POSIX 标准并且您的系统安装了该命令 -在这种情况下lsof可能的替代方案是- 您还可以使用(或改编)以下打印完整路径的脚本:lsofpid2path

#!/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}'
Run Code Online (Sandbox Code Playgroud)


Daw*_*žan 5

我尝试了许多不同的方法,对我来说最好的方法是:

ps -p $$

它也可以在Cygwin下工作,并且不能作为PID grepping产生误报。经过一些清理,它仅输出一个可执行文件名称(在Cygwin下带有路径):

ps -p $$ | tail -1 | awk '{print $NF}'
Run Code Online (Sandbox Code Playgroud)

您可以创建一个函数,这样就不必记住它:

# print currently active shell
shell () {
  ps -p $$ | tail -1 | awk '{print $NF}'
}
Run Code Online (Sandbox Code Playgroud)

...然后执行shell

经过Debian和Cygwin的测试。


小智 5

我在打印父进程时的变体:

ps -p $$ | awk '$1 == PP {print $4}' PP=$$
Run Code Online (Sandbox Code Playgroud)

当 AWK 可以为您完成时,不要运行不必要的应用程序。

  • 当 `ps -p "$$" -o 'comm='` 可以为您做到这一点时,为什么还要运行不必要的 `awk` 呢? (3认同)

小智 5

我的解决方案:

ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1
Run Code Online (Sandbox Code Playgroud)

这应该可以跨不同平台和 shell 移植。它像其他解决方案一样使用ps,但它不依赖于sedorawk并过滤掉管道及其ps自身中的垃圾,因此 shell 应该始终是最后一个入口。这样我们就不需要依赖不可移植的 PID 变量或选择正确的行和列。

我已经在 Debian 和 macOS 上使用 Bash、Z shell ( zsh) 和Fish进行了测试(如果不更改专门针对 Fish 的表达式,这些解决方案不适用于大多数解决方案,因为它使用不同的 PID 变量)。