如何识别脚本中使用的是bash还是dash?

如何识别脚本中使用的是bash还是dash?,bash,dash-shell,Bash,Dash Shell,我正在写一个bash脚本,在Ubuntu中使用“sh”命令时,它会抛出一个错误(它似乎与dash不兼容,我正在学习这个主题)。所以我想检测是否使用dash而不是bash来抛出错误 如何在脚本上下文中检测它?。甚至可能吗?您可以检查是否存在特定于shell的变量: 例如,bash定义了$bash\u版本。 由于在dash中运行时不会定义该变量,因此可以使用它进行区分: [ -n "$BASH_VERSION" ] && isBash=1 事后思考:如果希望避免依赖变量(可以想象

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


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

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

例如,
bash
定义了
$bash\u版本
。 由于在
dash
中运行时不会定义该变量,因此可以使用它进行区分:

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

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

下面的shell函数
getrueshellexename()
就是这样做的;例如,对于使用
sh
运行的脚本,它会在Ubuntu上返回
'dash'
(无论是显式还是通过shebang
#!/bin/sh
),因为
sh
dash
有符号链接

请注意,该函数的目标有两个:

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

  • 至少在一个平台上,OSX-
    sh
    不是符号链接,即使它实际上是
    bash
    。在那里,函数将在使用
    sh
    运行的脚本中返回
    'sh'
  • 该函数使用的是
    readlink
    ,虽然POSIX没有强制要求,但在大多数现代平台上都可以使用,尽管语法和功能有所不同。因此,使用GNU
    readlink
    -f
    选项来查找符号链接的最终目标不是一个选项。
    (我个人所知的唯一一个没有
    readlink
    实用程序的现代平台是HP-UX-请参阅,以了解可在所有POSIX平台上运行的递归readlink实现。)
  • 该函数使用
    ,该
    实用程序(除了在
    zsh
    中,它是一个内置的),它虽然不是POSIX强制要求的,但在大多数现代平台上都存在
函数的使用示例:

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

使用$0(即正在调用的shell的可执行文件的名称)

echo $0
给予

/usr/bin/dash
为了冲刺和

/bin/bash
对于bash。参数替换

${0##*/}

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

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

[[ 1 ]] 2>/dev/null && echo could be bash || echo not bash, maybe dash
可能是bash | | echo而不是bash,也许bash为我运行Ubuntu 19工作


在学校时曾学习过Pascal、Fortran和C语言,但需要熟练使用shell脚本

您可以做的是在脚本的第一行定义解释器:
#/当使用
/script.sh
调用时,bin/bash
将使其使用
/bin/bash
执行。还有,很高兴看到平克·弗洛伊德在附近:)你下一步在哪里进行直播?
bash
的功能是
dash
功能的超集
dash
更小更快,但主要局限于POSIX功能—请看,这不可靠。如果脚本是可执行的,并作为
/script
调用,该怎么办?如果脚本是源代码呢?$0被调用shell的任何程序设置为任意字符串。这几乎总是正确的……您可以使用
readlink-f
来获取符号链接的最终目的地,因此在源代码shell脚本(以
。/script
开始)中,可以使用
BIN=“$(readlink-f$0)”;BIN=“${BIN##*/}”
获取shell的名称,而不包含其路径。在执行的脚本(从
/script
开始)中,必须提取shebang,然后再提取符号链接…@zrajm:my shell函数的目的有两个:(a)可移植性和(b)在所有调用场景中工作。我已经更新了我的答案来澄清。您的建议不符合(a),因为例如,
readlink-f
是一个GNU扩展,它在OSX上不起作用。它不满足(b),因为分析shebang行是不够的-例如,您的脚本可以作为直接参数传递给任何shell可执行文件。@zrajm:此外,据我所知,没有简单的、与shell无关的方法来确定脚本是否正在源代码中(请告诉我您是否知道一种方法)。此外,例如,OSX将
-
前置到登录shell中
$0
中报告的shell可执行文件名(在OSX上,终端中创建的所有shell都是登录shell),因此您必须对此进行说明(这是最简单的部分)。
[[ 1 ]] 2>/dev/null && echo could be bash || echo not bash, maybe dash
echo $0 and [[ 1 ]] 2>/dev/null && echo