Script Valley
Bash Scripting for Developers
DevOps Scripting PatternsLesson 6.5

Building a self-contained Bash CLI tool

CLI tool structure, subcommand dispatch, help generation, version flag, --completion support, color detection, install and uninstall targets, Makefile integration, distributing Bash scripts

Structure of a Multi-Subcommand CLI

CLI subcommand dispatch structure

Real CLI tools use a dispatcher pattern: a main script that routes to subcommand functions or files based on the first argument.

#!/usr/bin/env bash
set -euo pipefail

VERSION="1.0.0"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

usage() {
  cat << EOF
mytool v${VERSION}

Usage: mytool  [options]

Commands:
  deploy    Deploy an application
  rollback  Roll back to previous version
  status    Show deployment status
  help      Show this message

Options:
  --version  Show version
  --help     Show help
EOF
}

main() {
  local cmd="${1:-help}"
  shift || true

  case "$cmd" in
    deploy)   source "${SCRIPT_DIR}/commands/deploy.sh"; cmd_deploy "$@" ;;
    rollback) source "${SCRIPT_DIR}/commands/rollback.sh"; cmd_rollback "$@" ;;
    status)   source "${SCRIPT_DIR}/commands/status.sh"; cmd_status "$@" ;;
    --version) echo "mytool $VERSION" ;;
    help|--help|-h) usage ;;
    *) echo "Unknown command: $cmd" >&2; usage; exit 1 ;;
  esac
}

main "$@"

Install Target

# In Makefile:
install:
	install -m 755 mytool /usr/local/bin/mytool
	install -d /usr/local/lib/mytool
	cp -r commands lib /usr/local/lib/mytool/

uninstall:
	rm -f /usr/local/bin/mytool
	rm -rf /usr/local/lib/mytool

For distribution, bundle everything into a single self-extracting script using a heredoc that writes the library files to a temp directory at runtime — useful when users can't run make install.