如何在旧版本的Bash上测试我的Bash脚本?

14

我正在开发一个Bash库,希望确保支持尽可能多的环境,包括旧版本的Bash安装。我的开发环境是Bash 4.3,但我的一些用户可能运行更老的版本,目前我没有办法确认或否认我的库是否能为他们工作。特别是我想兼容OSX(据我所知,它仍然使用Bash 3.2)。

我知道Bash可以在POSIX兼容模式下运行;是否有类似的设置来禁用现代功能?或者以某种兼容模式运行Bash?除了实际找到和启动旧操作系统并在那里测试我的库之外,我正在寻找任何技术方法。

更新

例如,我已避免使用关联数组,因为它们是在Bash 4中引入的,但如果没有测试,很难确定我是否意外地使用了其他Bash 4+功能。


1
http://travis-ci.org/ 可以让你在不需要本地安装的情况下,在不同环境矩阵中运行测试。首先,你可以设置不同版本的Debian,这些版本会引入不同版本的Bash。随着时间的推移,如果你真的想要完整的覆盖范围,你可以编译每个单独的点发布,并将其添加到矩阵中。 - tripleee
我几乎不认为在Bash中提供一个假设的“禁用新功能”选项会重新引入在版本之间修复的错误。 - tripleee
这是一个很好的建议;不幸的是我还没有到运行自动化测试的阶段 - 我正在尝试手动验证行为。至于重新引入错误,谁知道呢?IE的[兼容模式](https://en.wikipedia.org/wiki/Compatibility_mode)肯定会重新引入错误。虽然如果Bash有类似的功能,我会感到惊讶,但这就是我目前所设想的,所以我对其他替代方案也持开放态度。 - dimo414
1
我会获取Bash的下一版本源代码(例如3.25版本),并将其配置为安装在某个不起眼的地方(例如/usr/local/bin),然后编译和安装它 - 例如作为/usr/local/bin/bash-3.25。然后,您可以使用bash-3.25进行测试,而不仅仅是运行bash。从Linux迁移到Mac时,您更大的问题可能是非GNU实用程序。如果您使用GNU扩展选项(与POSIX特别是相比 - 或者仅仅是那些Mac不支持的选项),即使Bash完全理解您所说的话,您也会遇到问题。小心sed - Jonathan Leffler
@JonathanLeffler 关于非 GNU 工具的观点很有道理。我已经明确指出 GNU 工具是先决条件,所以这对我的特定情况并不构成问题。 - dimo414
4个回答

16

最终回到这个问题,只编译(不安装)你感兴趣的bash 版本相当简单。以下是我如何测试Bash 3.2.57:

$ mkdir ~/bash
$ cd ~/bash
$ wget http://ftp.gnu.org/gnu/bash/bash-3.2.57.tar.gz
$ tar xvzf bash-3.2.57.tar.gz
$ cd bash-3.2.57
$ ./configure
$ make
# if `make` fails due to yacc, run `sudo apt-get install byacc`
# No need to run `make install`
$ ./bash -version
GNU bash, version 3.2.57(1)-release (armv7l-unknown-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.

现在你有一个bash 3.2.57的二进制文件可以运行,而不需要实际“安装”它或修改您的正常环境。

要对此版本运行shell脚本:

$ ./bash your_script.sh

进入干净的交互式提示符,请执行以下操作:

$ env -i PATH="$PWD:$PATH" ./bash --noprofile --norc
bash-3.2$ bash -version
GNU bash, version 3.2.57(1)-release (armv7l-unknown-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.
bash-3.2$ 

使用env -i而不是直接调用./bash,可以让你得到一个几乎为空的环境(在 shell 中运行env以查看仍然设置了什么)。更新PATH允许调用bash(例如bash -version)来调用本地的bash shell,而不是系统范围内的安装(但请注意,这会拉入你整个的PATH)。添加--noprofile --norc避免加载你的.bashrc和相关脚本。

如果你不想选择任何PATH修改,只需在子shell中执行一次export PATH="$PWD:$PATH",而不是作为env命令的一部分。


我有一个Docker镜像repo)使用这些安装步骤,如果这对大家有帮助的话。我并不建议直接使用这个镜像,但你可以从Dockerfile/安装脚本中复制。采用MIT许可证。


5

虽然了解在本地编译任意版本的 bash 是件好事(就像在我的 其他回答 中所讨论的那样),但现在有一个更简单的选择——使用官方 Docker bash 镜像

要对脚本进行多个 bash 版本的测试通常很简单,只需执行:

for v in 3 4 5; do # or whatever versions you're interested in
  docker run -v "$PWD:/mnt" "bash:$v" \
    bash /mnt/your_script.sh
done

4

看一下shenv:https://github.com/shenv/shenv。与rbenv、pyenv、goenv等类似,但适用于shell。shenv可以让你安装不同版本的Bash以及其他(如zsh、fish、yash等)。

(免责声明:我就是将pyenv分叉成shenv的人!)


-1

您可以使用Bash自己的工具来模拟旧版本的Bash。在shopt中查找“compat”选项。

请注意,虽然它确实会根据手册页中每个compatNN条目所描述的更改行为,但它不会删除当前版本上存在的其他功能。例如,这不会导致任何错误:

shopt -s compat31
shopt -s globstar

尽管 globstar 仅在 Bash 4.0 中引入。


然而,正如该页面所指出的那样,这些“compatXX”设置仅会改变非常特定的行为;它不会导致Bash完全切换到给定版本的语法和语义。 compat31仅更改=〜[[ 的某些行为。值得注意的是,您仍然可以在启用了compat31的Shell中使用declare -A - dimo414
@dimo414 你为什么觉得需要重复我说的话? - Daniel C. Sobral
“使用Bash自己的功能来模拟旧版本的Bash [通过compat]”是不正确的。 compat标志不是模拟功能,而是向后兼容性功能。使用compat标志无法实现问题中所述的目标。 - dimo414
@dimo414 严谨地说,模拟意味着“复制(不同的计算机、软件系统等)的功能或操作”,这正是兼容标志所做的。你在评论中说的就是我在第二段中说的。也许你很生气,直接跳到评论区而没有真正阅读完整个答案?无论如何,你所说的一切都在我的回答中。 - Daniel C. Sobral
这里没有愤怒,你的帖子只是没有回答问题。意图是验证Bash脚本是否适用于旧版本的Bash。compat标志无法实现该目标。 - dimo414

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接