5

我正在编写一个 bash 脚本,在 Ubuntu 中使用“sh”命令时会引发错误(它似乎与 dash 不兼容,我正在学习这个主题)。所以我想检测是否使用 dash 而不是 bash 来引发错误。

如何在脚本上下文中检测到它?甚至可能吗?

4

4 回答 4

8

您可以检查是否存在特定于 shell 的变量

例如,bash定义$BASH_VERSION. 由于在运行时不会定义该变量dash,因此您可以使用它来区分:

[ -n "$BASH_VERSION" ] && isBash=1

事后思考:如果您想避免依赖变量(可以想象,可能设置不正确),您可以尝试获取运行脚本的 shell 可执行文件的最终名称,方法是确定调用可执行文件,如果它是符号链接,跟随它到达它的(最终)目标。

下面的shell 函数getTrueShellExeName()就是这样做的;例如,它将'dash'在 Ubuntu 上返回运行脚本sh(无论是显式还是通过 shebang #!/bin/sh),因为sh符号链接到dash那里。

请注意,该函数的目标是双重的:

  • 便携
    • 使用所有与 POSIX 兼容的(类 Bourne)shell,
    • 至少在大多数平台上,关于使用哪些实用程序和选项 - 请参阅下面的警告。
  • 所有调用场景中工作:
    • 来源(无论是否来自登录外壳)
    • 通过shebang线独立执行
    • 通过作为文件名参数传递给 shell 可执行文件来执行
    • 通过将其内容通过标准输入管道传输到 shell 可执行文件来执行

注意事项

  • 在至少一个平台上 - OSX -sh不是符号链接,即使它是有效的bash. 在那里,该函数将'sh'在运行的脚本中返回sh.
  • 该函数使用readlink,虽然 POSIX 没有强制要求,但在大多数现代平台上都存在 - 尽管具有不同的语法和特性。因此,使用 GNUreadlink-f选项来查找符号链接的最终目标不是一种选择。
    (我个人知道的唯一没有实用程序的现代平台HP readlink-UX - 请参阅https://stackoverflow.com/a/24114056/45375了解应该适用于所有POSIX 平台的递归读取链接实现。 )
  • 该函数使用which实用程序(除了 in zsh,它是内置的),虽然 POSIX 没有强制要求,但大多数现代平台上都存在该实用程序。

函数使用示例:

[ "$(getTrueShellExeName)" = 'bash' ] && isBash=1 

壳牌功能getTrueShellExeName()

getTrueShellExeName() {
  local trueExe nextTarget 2>/dev/null # ignore error in shells without `local`
  # Determine the shell executable filename.
  trueExe=$(ps -o comm= $$) || return 1
  # Strip a leading "-", as added e.g. by OSX for login shells.
  [ "${trueExe#-}" = "$trueExe" ] || trueExe=${trueExe#-}
  # Determine full executable path.
  [ "${trueExe#/}" != "$trueExe" ] || trueExe=$([ -n "$ZSH_VERSION" ] && which -p "$trueExe" || which "$trueExe")
  # If the executable is a symlink, resolve it to its *ultimate*
  # target. 
  while nextTarget=$(readlink "$trueExe"); do trueExe=$nextTarget; done
  # Output the executable name only.
  printf '%s\n' "$(basename "$trueExe")"
}
于 2014-04-11T11:38:34.073 回答
5

使用 $0 (即被调用的 shell 的可执行文件的名称)。例如命令

echo $0

/usr/bin/dash

对于破折号和

/bin/bash

对于 bash。参数替换

${0##*/}

只给出“破折号”或“bash”。这可以在测试中使用。

于 2014-04-11T14:55:50.037 回答
1

另一种方法可能是测试外壳功能是否可用,例如给出一个想法......

[[ 1 ]] 2>/dev/null && echo could be bash || echo not bash, maybe dash
于 2014-04-16T15:22:13.520 回答
-1
echo $0 and [[ 1 ]] 2>/dev/null && echo 

可能是 bash || echo 不是 bash,也许 bash 对我运行 Ubuntu 19 有用。

在学校学过一点 Pascal、Fortran 和 C,但需要熟练掌握 shell 脚本。

于 2019-11-30T15:09:32.513 回答