Self-Contained Bash Scripts
One of the habits I've been trying to reduce is my reliance on Bash History to remember how to perform certain tasks. Inside a terminal, we have an endless amount of generic tools we can use, but they all lack context specific to our needs, making them difficult to recall, especially as the task gets more complex. In this post, I'll be using the history of maptiles as an example.
My initial solution to relying on Bash History was documentation. If I relied on a command multiple times, I'll document it with some context. "How to fix colours in an image", "How to split an image into tiles", etc. This worked in the short-term. The problem with using documentation is that you need to remember that it was documented and what to look for. So after some weeks of not needing the documentation, I just forgot about it.
The next solution was to create a script for the task. Instead of remembering to search for specific steps, I ran the script. If I needed more steps, I added them. Simple enough. I'll create a script called ~/repos/im-map-tiles/im-map-tiles.sh
which takes an image and generates map tiles in a directory. Again, worked in the short-term for known use cases.
Over the course of a few years:
- I forgot what the script was capable of. So I wrote some test cases.
- The ordering of the growing list of optional arguments was getting hard to remember so I moved them over to flags.
- Remembering a fixed location for the script made it hard to re-use on other machines. So I symlinked it under
~/.local/bin
which is typically already setup under$PATH
. - The
im-
prefix made the context tied to ImageMagick rather than the tasks at hand. So I renamed it to justmaptiles
- Having to remember if I had the latest script was difficult so I introduced a
--version
and a release step. - Having to maintain both a detailed README and a common
--help
flag was tedious so I moved it all into the script and generated the README on release for the repository.
At the end of all of this, I have a self-contained script that contains all of the information I need.
It's worth mentioning that this gradual build of up of changes was the result of solving problems as they appeared, not before or after. If I was to take the resulting structure of maptiles
and apply it to all future tasks, it'll mostly be a waste of present time. Those tasks don't have the problems maptiles
has faced so far and it would be premature to write and maintain flags, tests, releases, installations for them. But when those problems do start to appear, self-contained scripts provide a nice template with no meta dependencies.
I could take this further. For example, the test cases can be used to generate the "Examples" section in the --help
output. The install.sh
and uninstall.sh
scripts can be moved to an --install
and --uninstall
flag. And so on. But it's not needed right now.
Thanks for reading.