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.
Conversative Updating
Fetch, Execute, Done
Supports multiple versions of the same module
You can always get the latest static version of Module.sh from:
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"
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.
Other good reasons to use Module.sh
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.
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.