skeleton:bash is a small, declarative framework that aims at providing the look-and-feel of any other *nix tool you and your users are used to. It offers a convenient way to structure and organize your bash scripts and assists you in writing versatile and easy-to-use programs.
Whats most important: it generates usage information for you and your scripts users.
For convenience you can simply install the script via npm, which adds the
skeleton-bash-path
command, returning the path to skeleton:bash.
#!/usr/bin/env bash
command -v skeleton-bash-path &> /dev/null || npm install -g --save skeleton-bash-npm
source "$(skeleton-bash-path)"
# ...
skeleton:bash makes it easy to
- parse and validate flag and parameter options
- generate extensive usage information
- write scripts with different sub commands
- setup and cleanup the environment
- debug and trace your script
In addition to that, it offers functions to colorize output and emit error messages.
Suppose this executable (chmod +x) example.sh
:
#!/usr/bin/env bash
source skeleton.sh
function @greet() {
description "Displays a greeting"
param "name" "n" "name" "greets <name> instead of the current user"; name="$param"
execute() {
echo "Hello ${name:-$(whoami)}"
}
}
Executing the greet command
The greet command will receive the parameter name|n
and also shows them when
running ./example.sh greet --help
.
Also, the greet command is listed in the global help page:
Instead of using named parameters, your commands can also be configured to receive arguments:
function @greet() {
description "Displays a greeting"
args "NAME"
execute() {
echo "Hello ${1}"
}
help() {
echo "Greets the given NAME"
}
}
Since we added the help
function, a help message other than the default description
tells the user that he can provide the NAME argument.
Every @function
will be added as a command to your script. The script will fail, if
you don't provide a description. Nesting commands is a matter of renaming the command:
function @books() {
description "Book Management"
}
function @books-list() {
command "books list"
description "Lists books"
execute() {
:
}
}
function @books-create() {
command "books create"
description "Creates a book"
execute() {
:
}
}
Defining options is pretty straightforward in skeleton:bash:
function @command {
flag "s" "silent" "silences output"
declare silent=$flag # true if either -s or --silent is present, false otherwise
flag "v" "increases verbosity"
declare verbose=$flag # only true, when -v is set; short and long args are interchangeable
param "n" "name" "string" "sets the name"
declare name=${param:-default} # the value of -n or --name or just 'default'
# multiple values may be read with ${param[*]} or ${param[@]}
param "max-age" "integer" "sets max-age"
local max_age=${arg:-} # the value of --max-age if present
# ...
}
Short options can be passed with the shorthand syntax -abc
. If you provide an
option, that is not declared in your command an error message will be shown:
The global variables $flag
and $param
will hold the value directly after the
respective registering function has been called.
Options from command functions should be saved as global variables to remain usable
for the execute
function like shown in the example above.
There are a few special functions:
Function | Description |
---|---|
setup |
Bootstraps the script, can be used to define global options |
teardown |
Will be called when the script exits |
main |
Will be called instead of usage page when script is being called without command |
Notice: When using the teardown
function, it is necessary to call __main
at the bottom
of your script!
Function | Description |
---|---|
error |
Emits red error messages to stderr along with its origin function name |
debug |
Logs an orange/brown debug message |
colorize |
Colorizes output; can also be used as pipe |
red , green , blue , ... |
see above |
has_flag |
Sets $flag to true when the flag option exists, false otherwise |
get_param |
Sets $param to the param values if present |
array_contains |
Returns true if the array $2 contains $1 |
When called with DEBUG
set to one of 1
, true
, yes
or y
, debug messages
are shown and colorized. They are formatted like:
[DEBUG] <script-name> <command_function>: <message>
Since debugging of bash script can be pretty hard, you can also enable tracing by
supplying the TRACE
parameter just like the debug parameter, which will enable
tracing as soon as the script enters your command.
function @hello() {
description "Hello world"
execute() {
debug "Command @hello started"
echo "Hello world"
}
}