Module.sh

Module.sh

Composable and Robust
Shell Scripts

Why

Reusing shell scripts is hard as packaging is often complicated by itself and therefore they live scattered all over our disks and when we need a specific one the search begins.

Module.sh is set to improve upon that situation. It can fetch the required script easily from the internet, either at runtime or it can build you a script which embeds all its script dependencies.

While that might sound like it has a few challenges by its own, Module.sh does so while caching fetched scripts and checking checksums before execution.

#!/bin/sh
# yes, we aim to be POSIX compliant

# loading module.sh, if curl+eval is a problem, there are ways to avoid them
eval "$(curl -fsL "https://mdl.sh/latest")"

# using module.sh to load the hello-world module
module "helloWorld" "https://mdl.sh/misc/hello-world/hello-world-1.0.1.sh" "cksum-3769348439"

# executing the loaded module
helloWorld

If you don’t want to rely on an external service: you don’t have to. Actually, there are many reasons to host your scripts on your own server.

Features

Robust

Conversative Updating

Easy to Use

Fetch, Execute, Done

Conflict Free

Supports multiple versions of the same module

Downloads

Manual Download

You can always get the latest static version of Module.sh from:

https://mdl.sh/latest

Just download it and save it as module.sh. To use Module.sh in your script you have to source it like that:

. ./module.sh

If you want to load it relative to your script and not relative to your current work directory you can use something like:

. "$(dirname "$(readlink -f "$0")")/module.sh"

Dynamic Script

If you want to let your script download the latest version of Module.sh during execution you can use the following snippet:

eval "$(curl -fsL "https://mdl.sh/latest")"

After that line, you can use the module command. The upside of this approach is the ease of use. The downside is that it will not work when the server fails and under certain circumstance can lead to executing some server error message (if curl doesn’t fail). So this is nice for playing around, but should not be used in production.

Reasons

Other good reasons to use Module.sh

Scope

When your scripts become larger you often struggle with the fact that every variable name is part of the global scope (even the ones within functions). An easy fix is to use the local keyword. But did you know that local is not POSIX compliant?

Module.sh solves the issue by isolating every module within its own Sub-Shell. That way you can keep using global variable names, as global gets limited to your module.

Compatibility

Did you know that a simple statement like echo "Error Message" >/dev/stderr is not POSIX compliant? (/dev/stderr is not part of POSIX)

Similar to e.g. Javascript, shell code is supposed to run on a variety of different operating systems and shells. Therefore, reusing high quality modules and improving the quality of existing ones is quite helpful and makes life easier.