如何在旧版本的 Bash 上测试我的 Bash 脚本?
How can I test my Bash script on older versions of Bash?
我正在开发一个 Bash 库,并希望确保我支持尽可能多的环境——包括 Bash 的旧安装。我的开发环境是 Bash 4.3,但我的一些用户很可能使用 运行 更旧的版本,目前我无法确认或否认我的库是否适用于他们。特别是我想与 OSX 兼容(它仍然与 Bash 3.2,AFAIK 一起提供)。
我知道 Bash 可以 运行 在 POSIX 兼容模式下;是否有类似的设置来禁用现代功能?或者在某种兼容模式下 运行 Bash 的方法?除了实际查找和启动旧操作系统并在那里测试我的库之外,我正在寻找任何技术。
更新
例如,我避免使用 associative arrays,因为它们是在 Bash 4 中引入的,但如果不进行测试,很难确定我没有不小心使用其他 [=23] =] 4+ 功能。
终于回到这个问题,编译(无需安装)您感兴趣的 bash version(s) 非常容易。这是我测试 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
输入clean interactive prompt:
$ 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
会给您留下一个几乎是空的环境(运行 env
从 shell 内部查看什么仍然设置)。更新 PATH
允许调用 bash
(例如 bash -version
)来调用本地 bash shell,而不是系统范围的安装(但请注意,这会引入你的整个路径)。添加 --noprofile --norc
可避免加载您的 .bashrc
和相关脚本。
如果您不想获取任何 PATH
修改,只需在 subshell 中执行一次 export PATH="$PWD:$PATH"
而不是作为 env
命令的一部分.
我有一个 Docker image (repo) 使用这些安装步骤,如果这对人们参考有帮助的话。我不一定建议直接使用此图像,但欢迎您从 Dockerfile/install 脚本中复制。 MIT 许可。
看看shenv:https://github.com/shenv/shenv。就像 rbenv、pyenv、goenv 等,但对于 shell,它允许您安装不同版本的 Bash 等(zsh、fish、yash 等)。
(免责声明:我是将 pyenv 分叉到 shenv 的人!)
您可以使用 Bash 自己的工具来模拟旧版本的 Bash。在 shopt
.
上查找 "compat" 选项
请注意,虽然它确实改变了手册页中每个 compatNN
条目下描述的行为,但它不会删除当前版本中存在的其他功能。例如,这不会导致任何错误:
shopt -s compat31
shopt -s globstar
尽管 globstar
仅在 Bash 4.0 上引入。
尽管很高兴知道可以在本地编译 bash 的任意版本(如我在 ), these days there's a much simpler option - the official Docker bash
images.
中所讨论的)
针对多个 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
我正在开发一个 Bash 库,并希望确保我支持尽可能多的环境——包括 Bash 的旧安装。我的开发环境是 Bash 4.3,但我的一些用户很可能使用 运行 更旧的版本,目前我无法确认或否认我的库是否适用于他们。特别是我想与 OSX 兼容(它仍然与 Bash 3.2,AFAIK 一起提供)。
我知道 Bash 可以 运行 在 POSIX 兼容模式下;是否有类似的设置来禁用现代功能?或者在某种兼容模式下 运行 Bash 的方法?除了实际查找和启动旧操作系统并在那里测试我的库之外,我正在寻找任何技术。
更新
例如,我避免使用 associative arrays,因为它们是在 Bash 4 中引入的,但如果不进行测试,很难确定我没有不小心使用其他 [=23] =] 4+ 功能。
终于回到这个问题,编译(无需安装)您感兴趣的 bash version(s) 非常容易。这是我测试 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
输入clean interactive prompt:
$ 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
会给您留下一个几乎是空的环境(运行 env
从 shell 内部查看什么仍然设置)。更新 PATH
允许调用 bash
(例如 bash -version
)来调用本地 bash shell,而不是系统范围的安装(但请注意,这会引入你的整个路径)。添加 --noprofile --norc
可避免加载您的 .bashrc
和相关脚本。
如果您不想获取任何 PATH
修改,只需在 subshell 中执行一次 export PATH="$PWD:$PATH"
而不是作为 env
命令的一部分.
我有一个 Docker image (repo) 使用这些安装步骤,如果这对人们参考有帮助的话。我不一定建议直接使用此图像,但欢迎您从 Dockerfile/install 脚本中复制。 MIT 许可。
看看shenv:https://github.com/shenv/shenv。就像 rbenv、pyenv、goenv 等,但对于 shell,它允许您安装不同版本的 Bash 等(zsh、fish、yash 等)。
(免责声明:我是将 pyenv 分叉到 shenv 的人!)
您可以使用 Bash 自己的工具来模拟旧版本的 Bash。在 shopt
.
请注意,虽然它确实改变了手册页中每个 compatNN
条目下描述的行为,但它不会删除当前版本中存在的其他功能。例如,这不会导致任何错误:
shopt -s compat31
shopt -s globstar
尽管 globstar
仅在 Bash 4.0 上引入。
尽管很高兴知道可以在本地编译 bash 的任意版本(如我在 bash
images.
针对多个 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