#!/bin/bash # Private implementation of bar subcommand _bar() { echo "foo_value is $foo_value" echo "flag_value is $flag_value" echo "1: $1" echo "2: $2" echo "3: $3" } # CLI Subcommands Implementation subcommands=() # foo subcommand, simple subcommands+=("foo") foo() { echo "foo" echo "$@" } # bar subcommand, with arg parsing and private implementation invocation subcommands+=("bar") bar() { help_bar() { echo "bar subcommand" echo "--------------" echo echo "Example:" echo " $progname bar --foo value --flag " echo echo "Available options:" echo " -f, --foo Sets a foo value. Required." echo " --flag Enables the flag." echo " Path to file to process. Required." } bar_args=() flag_value=0 # parse named args while [[ $# -gt 0 ]]; do case "$1" in --help) help_bar && exit 0 ;; -f|--foo) if [ "$#" -gt 1 ]; then shift foo_value="$1" else echo "ERROR: $1 option requires a value." >&2 help_bar && exit 1 fi ;; --flag) flag_value=1 ;; *) bar_args+=("$1") ;; esac shift done if [[ ! "$foo_value" ]]; then echo "ERROR: --foo option is required." >&2 help_bar && exit 1 fi if [[ ! "$bar_args[0]" ]]; then echo "ERROR: is required." >&2 help_bar && exit 1 fi foo_value="$foo_value" flag_value="$flag_value" _bar "${bar_args[@]}" } # CLI Main Implementation progname=$(basename $0) is_function() { declare -Ff "$1" >/dev/null; } help_commands() { echo "Available Commands:" for command in "${subcommands[@]}"; do echo " $command" done echo "" echo "Example:" echo " $progname $subcommands --help" } if [ "$#" -eq 0 ]; then echo "ERROR: No command specified." >&2 help_commands && exit 1 fi case "$1" in --help) help_commands && exit 1 ;; *) subcommand="$1" && shift if ! is_function "${subcommand}"; then echo "ERROR: Unknown command '${subcommand}'" >&2 help_commands && exit 1 fi "${subcommand}" "$@" exit $? ;; esac