DEV Community

Cover image for A "POSIX Playground" Container for Shell Script Testing
Jonathan Bowman
Jonathan Bowman

Posted on • Updated on • Originally published at bowmanjd.com

A "POSIX Playground" Container for Shell Script Testing

After exploring portable scripting in the previous article, I built a container available on Docker Hub, useful for testing and experimentation.

The container is an Alpine Linux container with the following tools:

  • posh shell (this is the default)
  • dash shell
  • rlwrap to offer readline support for either of the above shells (rlwrap posh is the default command if none specified)
  • checkbashisms for rooting out Bash-specific idiosyncrasies in scripts
  • shellcheck for shell script linting

See the "Writing Bash Scripts that are not only Bash" for explanation and usage of the above.

Using the container

(Podman also works fine in any of the examples below.)

First, pull the image:

docker pull docker.io/bowmanjd/posix-playground
Enter fullscreen mode Exit fullscreen mode

Note that the default user is shelly and the home directory is /home/shelly

To launch posh: Policy-compliant Ordinary SHell with readline support:

docker run -it bowmanjd/posix-playground
Enter fullscreen mode Exit fullscreen mode

To instead launch dash shell with readline support:

docker run -it bowmanjd/posix-playground rlwrap dash
Enter fullscreen mode Exit fullscreen mode

(Without rlwrap, line editing in either of these shells is impossible, making experimentation rather painful. Using rlwrap is recommended.)

Note that the container runs as an unprivileged user (as common sense dictates!) named shelly and the home directory is /home/shelly.

To make every file in the host's current working directory available from within the home directory inside the container, you might bind mount the current directory like this:

docker run -it -v "$(pwd):/home/shelly" bowmanjd/posix-playground
Enter fullscreen mode Exit fullscreen mode

If using rootless podman, you will find it convenient to add the :z SELinux label to the bind mount to indicate a shared volume, allowing read-write acces, then use the keep-id user namespace in order to map the user id of shelly to your current user, as follows:

podman run -it --userns=keep-id -v "$(pwd):/home/shelly:z" bowmanjd/posix-playground
Enter fullscreen mode Exit fullscreen mode

To check a helloworld.sh shell script in the current directory for "bashisms" (make sure the first line, the "shebang", reads #!/bin/sh):

cat helloworld.sh | docker run -i bowmanjd/posix-playground checkbashisms
Enter fullscreen mode Exit fullscreen mode

To check a helloworld.sh shell script in the current directory for a variety of gotchas:

cat helloworld.sh | docker run -i bowmanjd/posix-playground shellcheck -
Enter fullscreen mode Exit fullscreen mode

Be sure to include the - on the end: shellcheck - to let shellcheck know to expect stdin, as you are "piping" the script file contents into shellcheck as standard input.

To simply run a script using posh:

docker run -i -v "$(pwd):/home/shelly" bowmanjd/posix-playground posh myscript.sh
Enter fullscreen mode Exit fullscreen mode

Posh: an obscure shell with great usefulness

Of the tools included in the image, posh is the winner for me. It is not available on every distro, so having a container available is quite convenient.

Posh is also quite strict, and this is the point. It does not have any syntactic sugar to make it more Bash-like. I feel quite reassured when a script runs correctly in posh.

If you have other tools to recommend, or want to reflect on your experiences with this container image, feel free to contact me!

Top comments (0)