Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I test my Bash script on older versions of Bash?

I'm working on a Bash library and want to ensure I'm supporting as many environments as possible - including old installations of Bash. My development environment is Bash 4.3, but some of my users may well be running much older versions and presently I have no way to confirm or deny that my library will work for them. In particular I'd like to be compatible with OSX (which still ships with Bash 3.2, AFAIK).

I know Bash can run in POSIX-compliant mode; is there a similar setting to disable modern functionality? Or a way to run Bash in some sort of compatibility mode? I'm looking for any technique short of actually finding and booting up old operating systems and testing my library there.

Update

For example, I've avoided using associative arrays since they were introduced in Bash 4, but it's hard to be sure without testing that I'm not accidentally using some other Bash 4+ feature.

like image 935
dimo414 Avatar asked Jan 15 '16 06:01

dimo414


People also ask

Is bash backwards compatible?

If you change your shell to sh on a modern Linux it will run, simply because you're likely using a POSIX-compliant shell. And because Bash is fully backward compatible with sh, the shell scripts written for sh work with Bash.

Is bash backwards compatible with SH?

The sh script will most like run on bash also without modifications as bash is backward compatible with sh.

How do you check if a bash script is already running?

Bash script to check if a script is already running. echo -e "The SCRIPT_NAME.sh script was already running!"


1 Answers

Finally coming back to this question, it's pretty easy to just compile (without installing) the bash version(s) you're interested in. Here's how I'm testing 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.

Now you have a bash 3.2.57 binary you can run, without actually "installing" it or modifying your normal environment.

To run a shell script against this version:

$ ./bash your_script.sh

To enter a 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$ 

Using env -i rather than just calling ./bash directly leaves you with a mostly-empty environment (run env from inside the shell to see what's still set). Updating the PATH allows calls to bash (e.g. bash -version) to invoke the local bash shell, not the system-wide installation (but note this pulls in your whole PATH). Adding --noprofile --norc avoids loading your .bashrc and associated scripts.

If you don't want to pick up any PATH modifications, just execute export PATH="$PWD:$PATH" once inside the subshell instead of as part of the env command.


I have a Docker image (repo) using these installation steps, if that's helpful for folks to reference. I wouldn't necessarily suggest using this image directly, but you're welcome to copy from the Dockerfile/install script. MIT licensed.

like image 146
dimo414 Avatar answered Oct 04 '22 00:10

dimo414