符合 checkbashisms 的方式来确定当前 shell

符合 checkbashisms 的方式来确定当前 shell

在我的 中.profile,我使用以下代码来确保仅在登录 shell 实际上时才获取与 Bash 相关的别名和函数是重击:

# If the current (login) shell is Bash, then
if [ "${BASH_VERSION:-}" ]; then
  # source ~/.bashrc if it exists.
  if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
  fi
fi

我目前正在将我的 shell 配置文件、脚本和函数置于版本控制之下。我最近还开始从 shell 脚本中删除随意的 Bashisms,这些脚本不能从 Bash 特定的功能中受益,例如,替换function funcname()funcname().

对于我的 shell 文件存储库,我配置了预提交checkbashisms运行Debian 实用程序的钩子开发脚本包存储库中的每个sh文件,以确保我不会无意中引入 Bash 特定的语法。但是,这会给我带来一个错误.profile

possible bashism in .profile line 51 ($BASH_SOMETHING):
if [ "${BASH_VERSION:-}" ]; then

我想知道是否有一种方法可以检查哪个 shell 正在运行,并且不会在checkbashisms.

我检查了清单POSIX 列出的 shell 相关变量希望其中之一可以用来显示当前的外壳。我还查看了交互式 Dash shell 中设置的变量,但同样未能找到合适的候选者。

目前,我已排除;.profile的处理。checkbashisms它是一个小文件,因此手动检查它并不困难。然而,在研究了这个问题之后,我仍然想知道是否有一种符合 POSIX 标准的方法来确定哪个 shell 正在运行(或者至少是一种不会导致checkbashisms失败的方法)。


进一步背景/说明

我将 shell 配置文件置于版本控制之下的原因之一是在我当前定期登录的所有系统上配置我的环境:Cygwin、Ubuntu 和 CentOS(5 和 7,使用 Active Directory 为用户验证)。我最常通过 X Windows/桌面环境和远程主机的 SSH 登录。但是,我希望这是面向未来的,并且尽可能减少对系统依赖项和其他工具的依赖。

我一直使用checkbashisms它来对 shell 相关文件的语法进行简单、自动的健全性检查。它不是一个完美的工具,例如,我已经对其应用了补丁,以便它不会抱怨command -v在我的脚本中使用。在研究过程中,我了解到该程序的实际目的是确保遵守 Debian 政策,据我所知,该政策基于 POSIX 2004 而不是 2008(或其 2013 修订版)。

答案1

通常用于$0此目的。在您链接的网站上,它是:

0
   (Zero.) Expands to the name of the shell or shell script.

答案2

你的

# If the current (login) shell is Bash, then
if [ "${BASH_VERSION:-}" ]; then
  # source ~/.bashrc if it exists.
  if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
  fi
fi

代码完全符合 POSIX 规范,并且是检查当前正在运行的最佳方法bash。当然,该$BASH_VERSION变量是特定于 bash 的,但这就是您使用它的具体原因!检查您是否正在运行bash

请注意,$BASH_VERSION将设置是否bash调用为bashsh。一旦您断言您正在运行bash,您就可以将[ -o posix ]其用作 shell 被调用的指示符sh(尽管当环境中存在 POSIXLY_CORRECT 或bash使用-o posix、 或环境中的 SHELLOPTS=posix 调用时也会设置该选项。但在所有这些情况下,bash都会表现得好像被称为sh)。


您可以使用的另一个变量是 ,除非传递该选项,$BASH_VERSION否则checkbashism似乎不会抱怨。这也是特定于您应该能够用来确定您是否正在跑步的人。-x$BASHbashbash


我还认为这并不是真正正确的使用checkbashisms.checkbashisms是一个帮助您编写可移植sh脚本的工具(根据shDebian 政策中的规范,POSIX 的超集),它有助于识别在符号sh链接到bash.

A.profile由不同的 shell 解释,其中许多不符合 POSIX 标准。通常,您不会使用、或具有更高级交互功能的shshell 作为登录 shell 。zshfishbash

bash并且zsh,当未调用 as 时sh以及当它们各自的配置文件会话文件 ( .bash_profile, .zprofile) 不符合 POSIX(尤其是zsh)但仍可读取时.profile

因此,您想要的不是 POSIX 语法.profile,而是与 POSIX 兼容的语法(for sh),bash并且zsh如果您曾经使用过这些 shell(甚至可能是 Bourne,因为 Bourne shell 也可以读取.profile,但在基于 Linux 的系统上并不常见) )。

checkbashisms肯定会帮助你找到答案巴什主义但可能不会指出与zsh或不兼容的 POSIX 语法bash

在这里,如果您想使用bash特定的代码(例如解决该错误的方法bash,它不会~/.bashrc在交互式登录 shell 中读取),更好的方法是这样做(在您放置公共会话的~/.bash_profile位置之前或之后)~/.profile初始化)。

答案3

通常 SHELL 环境变量告诉您​​默认的 shell。您不需要手动获取 .bashrc 文件(不正确,请参阅下面的更新),bash 应该自动执行此操作,只需确保它位于 $HOME 目录中即可。

另一种选择是执行以下操作:

 ps -o cmd= $$

这将告诉您当前进程的命令(不带参数,不带值的 = 将不会显示列标题)。输出示例:

 $ps -o cmd= $$
 bash
 $sh
 $ps -o cmd= $$
 sh

更新:

我纠正了! :)

.bashrc 并不总是像下面的评论中提到的那样来源https://stackoverflow.com/questions/415403/whats-the-difference- Between-bashrc-bash-profile-and-environment

因此,您可以将 .bashrc 移动到 .bash_profile 并查看是否有效,而无需进行测试。如果没有,请进行上述测试。

答案4

该问题询问用户的登录外壳以及当前的以安抚的方式外壳checkbashisms。如果这意味着用户登录的 shell,我会使用来自的 shell /etc/passwd,例如,

MY_UID=$(id -u)
MYSHELL=$(awk -F: '$3 == '$MY_UID'{ print $7; }' </etc/passwd )

用户当然可以在登录后启动一个新的shell。当然,如果一个是bash,另一个不是,则测试bash的环境变量可能没有帮助。

有些人可能想使用getent而不仅仅是文件passwd(但这不在问题的范围内)。

基于有关 LDAP 的评论和建议logname,可以使用这种替代形式:

MY_NAME=$(logname)
MYSHELL=$(getent passwd | awk -F: '$1 ~ /^'$MY_NAME'$/ {print $7;}' )

在测试它时,我注意到它logname不喜欢它的输入重定向(所以我将表达式分开)。快速检查显示getent应该在提到的平台上工作(尽管应该在原始问题中提供):

相关内容