【问题标题】:detect default interactive shell doesn't work on shell script检测默认交互式 shell 不适用于 shell 脚本
【发布时间】:2021-05-01 12:55:30
【问题描述】:

我使用zsh作为默认shell,我在终端上运行echo $0并得到-zsh,但是下面的代码无法检测到默认的交互式shell

#!/usr/bin/env bash

if [ -n "$ZSH_VERSION" ]; then
  echo "zsh"
elif [ -n "$BASH_VERSION" ]; then
  echo "bash"
else
  echo "others"
fi

检测结果总是bash,为什么?谢谢。

【问题讨论】:

  • 显示如何启动脚本。
  • @Cyrus run ./detect.sh
  • 好的,展示你的shebang。
  • @Cyrus 抱歉,我已经更新了代码块中的 shebang。从您的回答中,我意识到 shebang 导致了这个问题。如果我想使用这个shebang,我怎样才能检测到它?谢谢。
  • @Bill :您明确地将脚本编写为 bash 脚本。如果以这种方式运行它,则不涉及其他 shell。如果你将它调用为ksh detect.sh,它应该输出others

标签: bash shell zsh


【解决方案1】:

您的代码可用于检测 current shell。但是脚本在它们自己的 shell 中运行,独立于交互式 shell。由于它的 shebang,您的脚本文件始终在 bash 中运行。如果没有 shebang,调用 shell 将决定如何运行脚本(如果有的话)。

检测父shell

要检测调用脚本的 shell,请尝试

#!/usr/bin/env bash
ps -p $PPID -o comm=

当您运行交互式 zsh 并执行此文件时,您应该得到 zsh 作为输出。

检测默认外壳

您的问题的标题是关于检测 默认交互式 shell。为此,您不能检查任何进程,因为即使您的默认 shell 是 X,您也可以始终使用 Y。相反,请查看存储默认值的文件:

grep "^$USER:" /etc/passwd | cut -d: -f7

【讨论】:

  • IIRC,如果由于缺少shebang而无法执行脚本,bash 将使用bash 执行脚本,而不是/bin/sh。 Shebangs 没有标准化,只是很常见。
  • @chepner 感谢您的评论。好像你是对的。 Bash uses execve 仅适用于以#! 开头的二进制可执行文件和脚本(请参阅man execve)。如果execve 无法执行该命令,bash 会检查该文件并将其作为 bash 脚本本身运行。到目前为止,我认为如果 shebang 丢失,execve 会使用 sh。我修正了我的答案。
  • 这不适用于不将用户帐户保存在 /etc/passwd 中的操作系统(例如 macOS)。
【解决方案2】:

执行此操作的标准方法是使用 SHELL 环境变量:

echo "Your default shell is $SHELL"

这是在 POSIX 标准中定义的,section 8.3, "Other Environment Variables"

SHELL
该变量应代表用户首选的命令语言解释器的路径名。如果此解释器不符合 XCU Shell Command Language 中的 Shell 命令语言,则实用程序的行为可能与 POSIX.1-2017 中描述的不同。

【讨论】:

  • 只有当你专门设置你的shell来保证SHELL变量的存在时,它才能可靠地工作。 bash 似乎会自动执行此操作,但 zsh - 例如 - 不会,至少在我的实现中不会。当然我可以在/etc/zshenv中手动设置SHELLdashash 似乎也没有设置SHELL。我不知道 ksh 是如何处理这个的。
  • @user1934428 我没有进行广泛的测试,但它似乎在 macOS 下的每个 shell 中都适用于我(尽管我发现它在 cron 作业中正常工作,因为 Vixie cron 专门将 SHELL 设置为 /bin/sh,除非它在 ​​crontab 文件中被覆盖)。你用的是什么环境?
  • 在 Mac 上,这几乎是正确的(也许 BSD 构建的 shell 与 Linux 不同,或者 Mac 在 /etc/... 中默认提供了相应的设置) not 在 MacOS 上工作(至少对我而言),是启动一个 bash 登录 shell,并在其中打开一个非登录 zsh 子shell。在这种情况下,SHELL 仍然会显示 bash,尽管我们现在在 zsh 中。
  • @user1934428 这就是它应该做的——$SHELL 应该是在用户数据库中为当前用户设置的 shell(传统 unix 上的 /etc/passwd,/var/db/dslocal/nodes /默认/ macOS上的用户)。您可以通过将 Terminal.app 首选项中的 shell 从“默认登录 shell”更改为其他内容来测试这一点。 $SHELL 仍应显示用户的默认 shell,而不是您在终端首选项中选择的其他内容。
  • 我发现我误读了 OP 的问题:他想知道用户的默认登录 shell,而不是他当前使用的 shell。感谢您指出这一点!
猜你喜欢
  • 2010-10-31
  • 1970-01-01
  • 2011-08-31
  • 1970-01-01
  • 2016-05-29
  • 2015-06-29
  • 2015-12-26
  • 2013-09-12
  • 1970-01-01
相关资源
最近更新 更多