我正在编写一个 bash 脚本,在 Ubuntu 中使用“sh”命令时它会抛出错误(它似乎与 dash 不兼容,我正在学习这个主题)。所以我想检测是否使用 dash 而不是 bash 来抛出错误。
如何在脚本上下文中检测它?有可能吗?
You can 检查特定于 shell 的变量是否存在:
例如,bash
定义$BASH_VERSION
。
由于该变量在运行时不会被定义dash
,你可以用它来区分:
[ -n "$BASH_VERSION" ] && isBash=1
事后思考:如果你想避免依赖变量(可以想象,可能设置不正确),您可以尝试获得ultimateshell 可执行文件的名称通过确定调用的可执行文件来运行脚本,如果它是符号链接,则跟踪它到其(最终)目标。
The 外壳函数getTrueShellExeName()
下面就是这样做的;例如,它会返回'dash'
在 Ubuntu 上运行脚本sh
(无论是明确地还是通过 shebang#!/bin/sh
), 因为sh
符号链接到dash
there.
请注意,该函数的目标有两个:
-
Be portable:
- 与所有 POSIX 兼容(类似 Bourne)的 shell 一起使用,
- 至少跨越most平台,关于使用哪些实用程序和选项 - 请参阅下面的注意事项。
-
Work in all invocation scenarios:
- 来源(无论是否来自登录 shell)
- 通过 shebang 线独立执行
- 通过作为文件名参数传递给 shell 可执行文件来执行
- 通过将其内容通过 stdin 传送到 shell 可执行文件来执行
Caveats:
-
在至少一个平台上 - macOS -sh
不是符号链接,即使它是有效的bash
。在那里,函数将返回'sh'
在运行的脚本中sh
.
-
该函数使用readlink
,虽然 POSIX 没有强制要求,但存在于most现代平台——尽管如此具有不同的语法和功能。因此,使用 GNUreadlink
's -f
查找符号链接的选项ultimate目标是not一个选项。
(我个人知道的唯一一个现代平台not have a readlink
实用程序是 HP-UX - 请参阅https://stackoverflow.com/a/24114056/45375对于应该工作的递归读取链接实现allPOSIX 平台。)
-
该函数使用which
实用程序(除了zsh
,其中它是一个builtin),虽然 POSIX 没有强制要求,但存在于most现代平台。
-
Ideally, ps -p $$ -o comm=
would be sufficient to determine the path of the executable underlying the process, but that doesn't work as intended when directly executing shell scripts with shebang lines on Linux, at least when using the ps
implementation from the procps-ng
package, as found on Ubuntu, for instance: there, such scripts report the script's file name rather than the underlying script engine's.Tip of the hat to ferdymercury for his help.
Therefore, the content of special file /proc/$$/cmdline
is parsed on Linux, whose first NUL
-separated field contains the true executable path.
该函数的使用示例:
[ "$(getTrueShellExeName)" = 'bash' ] && isBash=1
外壳函数getTrueShellExeName()
:
getTrueShellExeName() {
local trueExe nextTarget 2>/dev/null # ignore error in shells without `local`
# Determine the shell executable filename.
if [ -r /proc/$$/cmdline ]; then
trueExe=$(cut -d '' -f1 /proc/$$/cmdline) || return 1
else
trueExe=$(ps -p $$ -o comm=) || return 1
fi
# Strip a leading "-", as added e.g. by macOS 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")"
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)