Search code examples
bashshellunixwhile-loopcommand-line-interface

Bash CLI that accepts multiple arguments


I am trying to create a custom CLI & I ran into a problem.

Here is my code.

#!/bin/bash

# Function definations.
__help_menu() {

      echo -e ""
      echo -e "======================="
      echo -e "THESE ARE THE AVAILABLE COMMANDS:"
      echo -e ""
      echo -e "⟹   ./cli.sh --create -domain example.com"
      echo -e "⟹   ./cli.sh --create -domain example.com -ssl <no|yes>"
      echo -e "⟹   ./cli.sh --create -domain example.com -ssl <yes|no> -wp <yes|no>"
      echo -e "⟹   ./cli.sh --delete -domain example.com"
      echo -e "⟹   ./cli.sh --delete -domain example.com -ssl <yes|no>"
      echo -e "======================="
      echo -e ""
}

__create() {

    # Do something. I got this.
    echo -e "I got this"
}

__delete() {

    # Do something. I got this.
    echo -e "I got this"
}

__cli() {

    # Run while loop.
    while [[ "$#" -gt 0 ]]; do
        case $1 in
            --create)
                shift
                case $1 in
                    -domain) 
                        DOMAIN_NAME="$2"; 
                        shift 
                        ;;
                    -ssl)
                        INSTALL_SSL="$2"; 
                        shift 
                        ;;
                    -wp|--wp) 
                        INSTALL_WP="$2"; 
                        shift 
                        ;;
                    *)
                    echo -e "Unknown parameter passed: $1";
                    __help_menu
                    exit
                    ;;
                esac
                ;;
            --delete)
                shift
                case $1 in
                    -domain) 
                        DOMAIN_NAME="$2"; 
                        shift 
                        ;;
                    -ssl)
                        DELETE_SSL="$2"; 
                        shift 
                        ;;
                    *)
                    echo -e "Unknown parameter passed: $1";
                    __help_menu
                    exit
                    ;;
                esac
                ;;
            --help) __help_menu; exit ;;
        *) echo -e "Unknown parameter passed: $1"; exit 1 ;;
        
        esac
        shift
    done
}

__cli "$@"

if [ "$1" == "--create" ]; then

    echo -e "Command is to create a new site."
    echo -e "Domain name: $DOMAIN_NAME"
    echo -e "Install SSL: $INSTALL_SSL"
    echo -e "Install WP: $INSTALL_WP"
    echo -e ""
fi

When I run ./cli.sh --create -domain example.com it's working fine. But when I run ./cli.sh --create -domain example.com -ssl yes it says Unknown parameter passed: -ssl. Where am I doing a mistake?

Another question:

What is the best way to replace ./cli.sh --create -domain hello.com with foo --create -domain hello.com so I can use the CLI from anywhere in the terminal.


Solution

  • Example how to use GNU getopt to simplify command line parsing:

    #! /bin/bash
    
    options=$(getopt -q -o '' -l domain:,ssl:,wp: -- "$@") || {
      printf 'ERROR: Invalid argument\n' >&2
      exit 1
    }
    eval set -- "$options"
    
    while true; do
      case "$1" in
        --domain) DOMAIN="$2"; shift 2;;
        --ssl)    SSL="$2";    shift 2;;
        --wp)     WP="$2";     shift 2;;
        --) shift; break;;
        *)  break;;
      esac
    done
    
    COMMAND=$1; shift
    
    case ${COMMAND:?missing} in
      create|delete)
        echo "$COMMAND" "${DOMAIN:?missing}" "${SSL:-yes}" "${WP:-yes}";;
      *)
        printf 'COMMAND: invalid\n' >&2; exit 1;;
    esac
    

    Usage:

    ./cli.sh create --domain http://example.com
    

    The default for --ssl and --wp is "yes".