我正在寻找一种简单可靠的方法来从脚本或源文件中获取当前 shell 的名称(不是从命令行)。我本来希望这样做$(basename "$SHELL")
,但是如果我的登录 shell 是zsh
并且我在 some_script.sh 中有以下代码
this_shell=$( basename "$SHELL" )
echo "The Shell is $this_shell"
echo "The Shell is $0"
我用 运行它bash some_script.sh
,它仍然列出zsh
而不是bash
即使使用的解释器是/bin/bash
.我不确定为什么 shell 设计者选择显示默认 shell 而不是当前 shell,但这似乎是我们所坚持的。
还有一些其他稍微类似的问题(这里和这里),但他们的答案在很多方面都有不足。
- 他们经常假设用户正在尝试找出他们当前正在使用的交互式 shell,但这是疯狂的。我知道我要在哪个 shell 中输入命令——我需要可以在任何地方运行的代码来确定哪个 shell它正在使用。
- 他们经常提供几种不同的东西来尝试——就像你在命令行上一样,可以随意摆弄,直到你知道你正在使用 bash——但我需要一件在所有情况下都可靠的东西。
- 他们经常提供脚本中完全无用的东西,例如
echo $0
.如上面的脚本所示,失败了。 (是的,它可以在交互式 shell 命令行中工作,但为什么您不知道您正在使用什么 shell?) - 他们有时会发出命令(在我有限的测试中)包括正确的信息,如
ps -p $$
,但缺乏跨平台、跨 shell 兼容的 sed/awk 命令来通过管道获取只是外壳名称并忽略随之而来的其他信息。 - 它们包括只能在几个 shell 上运行的东西,比如
$BASH_VERSION
和$ZSH_VERSION
。我想支持尽可能多的shell,比如fish
,,,csh
。tcsh
我如何可靠地和准确探测任何 当前的壳?我正在寻找能够跨平台、在脚本中以及尽可能多且合理的 shell 工作的东西1。
更新:当我发布这个问题时,我预计 shell 中内置了一些设施来为我们提供此信息,但事实似乎并非如此。既然现在看来不可避免地要依赖某些东西在外面贝壳,我应该更明确地说我要的是跨平台解决方案(虽然我对上面其他答案的反对暗示了这一点,但如果您不仔细阅读问题,可能很容易错过)。
更新2 如果有人仍然认为这与仅适用于 Linux 的问题重复,因为 Stéphane 的答案并非仅适用于 Linux,那么以下是我所要求的内容与他提供的内容之间的差异。 (请注意,他写的很巧妙,我不是敲它,但这并不能解决我的问题。)
- 我在找东西简单的和可靠的, 那
- 可以添加到任何脚本或函数定义(将由 a
.zshrc
或.bash_profile
或其他任何来源)来分支。 - 您不能使用他的脚本作为将解释器名称传递给调用脚本/函数的外部实用程序,因为它始终由默认解释器解释并返回。这使得它很难或不可能用于我的目的。如果可能的话,仍然非常非常困难,而使其发挥作用的解决方案是不是答案中给出。因此他没有回答我的问题,因此它不是重复的。
如果你想看一些东西将要工作,看看GitHub 上的 ShellDetective。这可能会让您更容易看到 SE 上已经存在的内容与该问题正在寻找的内容之间的差异(实际上是为了满足该问题的需求而编写的,而其他任何地方都未满足该需求)。
(PS,如果你不相信有这样的用例,想象一下函数被源到.zshrc
、.bash_profile
、 或.profile
取决于正在使用的服务器以及它有哪些可用的 shell。它们是源代码的,所以它们没有 shebang 行。它们如果它们可以在任何 shell 中工作,那么它们是最有用的,但有时它们必须知道它们在哪个 shell 中才能知道如何运行。)
1我不关心那些不是任何传统意义上的贝壳的“贝壳”。我不关心某个人为自己写的一些 shell。我只关心真正的贝壳这实际上是在野外发生的,可以想象有人在登录某些服务器时可能必须使用它,而他们不能在上面安装任何他们想要的 shell。
答案1
答案2
所以我仍在努力充实这一点,但我认为我有一个可行的想法。正如您所注意到的,您想要做的事情即使不是不可能,也是极其难以在所有 shell 中完成的(您添加到多语言的每个变体都会以大于线性的速度增加复杂性)。如果你分成 Bourne(sh、ash、dash、bash、ksh、pdksh、zsh 等)和 c 风格 shell(csh、tcsh、fish 等),你可能可以做到这一点,但csh
变体之间的变化呈现出各种有趣的变化挑战。
因此,让我们用已知语言(带有 shebang 行的 bash、C、perl、python 等)编写检测例程,并确定父级可执行文件的名称。然后,我们可以使用两个技巧将信息返回给父级,即返回值和写入标准输出的单个单词。在 sh 下降的 shell 上,我们将返回 0 并写入 shell 的名称,因为它们都有良好的反引号处理。在 C 系列 shell 上,我们可以开始增加需要解决的每组不兼容性的返回值。返回值超过 200 将指示错误,从一切开始似乎都很好,但在 200 时我无法分辨出我的父母是谁。
内部程序在linux上看起来很简单(/proc/ppid/exe
成功了一半)。我很确定这可以在 bsd 上使用 ps 选项完成,但我目前没有正在运行的 bsd 系统来测试,而且我的 mac 需要一个新的硬盘(无论如何只有 10.4)。尽管它显着减少了 shell 语法问题,但它确实引入了一组不同的兼容性问题。我仍然认为它有可能性。
答案3
尝试这样的事情
shell_bin=$(ps h -p $$ -o args='' | cut -f1 -d' ')
echo $shell_bin
答案4
这个怎么样,抱歉,我没有很多平台可以尝试
local __shell=`ps $$ -o comm=""`