Build a Custom CLI with Bash
When we say “CLI” we’re talking about a program that we can run at the command line by simply typing the command name and its parameters.
When modern languages like Ruby, Python or Go are not available or not allowed due to compliance rules, Bash scripting is the way to go if you want to build a custom CLI and be sure that it runs on a variety of systems.
Bash (
bash
) is one of many available (yet the most commonly used) Unix shells. Bash stands for "Bourne Again SHell", and is a replacement/improvement of the original Bourne shell (sh
).
Source: https://askubuntu.com/a/172487
Here we are building a modular CLI with a configuration file and (sub-) commands including help and usage instructions using Bash compliant scripts.
A name to command them all via parameters
First we choose a name and think about the commands and its parameters. The CLI in this example should deploy a series of applications to a Kubernetes Cluster via Helm in the end. Your use case could be something different ;)
We call the CLI bagcli
which stands for Brot and Games CLI and have a final view of the command line in our minds — this should be the output of calling bagcli
without a command or when a command is misspelled.
$ ./bagcli
bagcli
Brot and Games CLI
Version: 0.1.0
Usage: bagcli [command]
Commands:
deploy Deploy
* Help
The command bagcli deploy
should have its own usage instructions which should also be shown if the parameter <project_name>
is missing.
$ ./bagcli deployCommand: deployUsage:
deploy project_name
Modular directory structure
Next we decide upon the directory structure for our CLI. Since we are building a modular CLI with one file for each (sub-) command, we need a clean directory structure.
/path/to/bagcli/
├── VERSION
├── bagcli
├── commands
│ └── deploy
├── common
└── config.template
The resulting Bash scripts and files in detail
bagcli
is the entrypoint script which loads the config and decides upon the command/parameters which file to execute from thecommands
directory.
Example:bagcli deploy <project_name>
processes the command and the parameter and callscommands/deploy
with parameter<project_name>
.commands/deploy
has its own help and usage instructions. It takes the parameter<project_name>
and callshelm
with parameters.common
holds all the functions which all the scripts need (eg. for logging).config.template
is like the name says a template for easy configuration of the CLI by the end-user. Users are instructed tocp config.template config
and update the file according to their needs. The fileconfig
should be ignored by version systems like Git due to possible sensitive data.
Following is a basic implementation of the core files: bagcli
, commands/deploy
, common
and config.template
.
Conclusion
The final result is an extensible CLI bagcli
with currently one command bagcli deploy
implemented.
It can be easily extended by cp commands/deploy commands/my_command
and editing the commands/my_command
file to fit your needs. Don’t forget to hook it up in the case statement in the bagcli
file (entrypoint for all commands).
There is also a GitHub repository where you can find an up-to-date version with better error handling and other improvements.
https://github.com/brotandgames/bagcli
You can use it as a blueprint or skeleton for your projects.
This article has been submitted to Hacker News and reddit on the 4th of May 2019.
Thanks for reading.