Skip to content

Instantly share code, notes, and snippets.

@clemtibs
Last active November 13, 2023 10:48
Show Gist options
  • Select an option

  • Save clemtibs/5f97039fc25b03be76f17d13b1a05a03 to your computer and use it in GitHub Desktop.

Select an option

Save clemtibs/5f97039fc25b03be76f17d13b1a05a03 to your computer and use it in GitHub Desktop.

Revisions

  1. @brianclements brianclements revised this gist Feb 3, 2021. 1 changed file with 71 additions and 71 deletions.
    142 changes: 71 additions & 71 deletions Bash Script.sh
    Original file line number Diff line number Diff line change
    @@ -1,19 +1,19 @@
    #!/bin/bash
    ##----------------
    export script_name=$(basename -a "$0")
    export script_short_desc="
    export _script_name=$(basename -a "$0")
    export _script_short_desc="
    A script for doing things."
    export script_mod_date='0000.00.00-00:00'
    export script_version='0.0.1'
    export script_requirements='none'
    export script_bash_debug=false
    export _script_mod_date='0000.00.00-00:00'
    export _script_version='0.0.1'
    export _script_requirements='none'
    export _script_bash_debug=false
    ##----------------
    shopt -s extglob ## Needed for arg parsing

    ## Internal config
    export script_subcommands_args=()
    export script_min_args=1
    export script_max_args=1
    export _script_subcommands_args=()
    export _script_min_args=1
    export _script_max_args=1

    ## Script Config
    export working_dir=${working_dir:-"$PWD"}
    @@ -26,125 +26,125 @@ do_work() {
    }

    ## Args
    parseArgs() {
    local args=("$@")
    while (( "${#args}" )); do
    _parse_args() {
    local _args=("$@")
    while (( "${#_args}" )); do
    case "$1" in
    -@([a-z|A-Z]*))
    # Switches
    parseSwitches "$1"
    _parse_switches "$1"
    ;;
    --*)
    # Options
    parseOptions "$1"
    _parse_options "$1"
    ;;
    *)
    # Subcommands args stored as an array for later. For more
    # complicated scripts, sometimes we need to act on the
    # switches/options or source configuration first before we run
    # the subcommands.
    script_subcommands_args=("$@")
    _script_subcommands_args=("$@")
    break
    ;;
    esac
    shift
    args=("$@")
    _args=("$@")
    done
    shopt -u extglob
    # Check for minimum number of arguments/subcommands beyond switches and options here.
    if [[ ${#script_subcommands_args[@]} < $script_min_args ]]; then
    echo "Syntax error: a minimum of $script_min_args arguments required."
    if [[ ${#_script_subcommands_args[@]} < $_script_min_args ]]; then
    echo "Syntax error: a minimum of $_script_min_args arguments required."
    echo ""
    usage_short
    _usage_short
    exit 1
    fi
    if [[ ${#script_subcommands_args[@]} > $script_max_args ]]; then
    echo "Syntax error: only $script_max_args argument allowed."
    if [[ ${#_script_subcommands_args[@]} > $_script_max_args ]]; then
    echo "Syntax error: only $_script_max_args argument allowed."
    echo ""
    usage_short
    _usage_short
    exit 1
    fi
    }

    parseSwitches() {
    local switches="$1"
    switches="${switches:1}"
    while (( "${#switches}" )); do
    _parse_switches() {
    local _switches="$1"
    _switches="${_switches:1}"
    while (( "${#_switches}" )); do
    # Handle actions for individual switches here
    case "${switches:0:1}" in
    case "${_switches:0:1}" in
    h)
    usage_short
    _usage_short
    exit 0
    ;;
    v)
    version
    _version
    exit 0
    ;;
    *)
    echo "Error: \"${switches:0:1}\" not a valid switch"
    echo "Error: \"${_switches:0:1}\" not a valid switch"
    echo ""
    usage_short
    _usage_short
    exit 1
    ;;
    esac
    switches="${switches:1}"
    _switches="${_switches:1}"
    done
    }

    parseOptions() {
    local option=( $( IFS='='; echo ${1} ) )
    local option_keyword=${option[0]:2}
    _parse_options() {
    local _option=( $( IFS='='; echo ${1} ) )
    local _option_keyword=${_option[0]:2}
    # Get value of option if there is any
    local option_value=${option[@]:1}
    local _option_value=${_option[@]:1}
    # Handle actions for individual options here
    case "${option_keyword}" in
    case "${_option_keyword}" in
    bash-debug)
    script_bash_debug=true
    _script_bash_debug=true
    ;;
    help)
    usage
    _usage
    exit 0
    ;;
    version)
    version
    _version
    exit 0
    ;;
    *)
    echo "Error: \"${option_keyword}\" not a valid option"
    echo "Error: \"${_option_keyword}\" not a valid option"
    echo ""
    usage_short
    _usage_short
    exit 1
    ;;
    esac
    }

    parseSubcommands() {
    local args=("$@")
    while (( "${#args}" )); do
    _parse_subcommands() {
    local _args=("$@")
    while (( "${#_args}" )); do
    case "$1" in
    work)
    echo "Args passed to work command: ${args[@]:1}"
    echo "Args passed to work command: ${_args[@]:1}"
    break
    ;;
    *)
    echo "Error: "$1" not a valid subcommand"
    usage
    _usage
    exit 1
    ;;
    esac
    shift
    args=("$@")
    _args=("$@")
    done
    }

    ## Dialogs
    usage_cli=$(cat <<EOF
    Usage: ${script_name} [<switches>...] [<option keyword>=<value>...] <subcommand> <subcommand args>
    ${script_short_desc}
    _usage_cli=$(cat <<EOF
    Usage: ${_script_name} [<switches>...] [<option keyword>=<value>...] <subcommand> <subcommand args>
    ${_script_short_desc}
    EOF
    )

    usage_args=$(cat <<EOF
    _usage_args=$(cat <<EOF
    Switches/Options:
    --bash-debug Show bash debug info for *most* of the non-template part
    @@ -160,19 +160,19 @@ Subcommands
    EOF
    )

    usage_short() {
    _usage_short() {
    cat <<EOF
    ${usage_cli}
    ${_usage_cli}
    ${usage_args}
    ${_usage_args}
    Run '${script_name} --help' for the full help documentation.
    Run '${_script_name} --help' for the full help documentation.
    EOF
    }

    usage() {
    _usage() {
    cat <<EOF
    ${usage_cli}
    ${_usage_cli}
    Switches can be combined, or used individually, in any order. Options must
    follow the format --option="something here" and not have spaces in between
    @@ -185,39 +185,39 @@ By default:
    "exit" is declared in any of the 'case' statements. This is the current
    behavior but can be easily changed.
    ${usage_args}
    ${_usage_args}
    Requirements:
    ${script_requirements}
    ${_script_requirements}
    Version:
    ${script_name} version: ${script_version}
    Last modifed on: ${script_mod_date}
    ${_script_name} version: ${_script_version}
    Last modifed on: ${_script_mod_date}
    EOF
    }

    version() {
    echo "${script_name} version: ${script_version}"
    echo "Last modifed on: ${script_mod_date}"
    _version() {
    echo "${_script_name} version: ${_script_version}"
    echo "Last modifed on: ${_script_mod_date}"
    }

    ## Sequence
    main() {
    parseArgs "$@"
    _main() {
    _parse_args "$@"
    # I realize this only effects the non-template part of the script; this is usually fine.
    # If you really want to debug the entire thing, then move `set -x` above `parseArgs "$@"`
    if $script_bash_debug; then
    # If you really want to debug the entire thing, then move `set -x` above `_parse_args "$@"`
    if $_script_bash_debug; then
    set -x
    else
    set -eo pipefail
    fi
    parseSubcommands "${script_subcommands_args[@]}"
    _parse_subcommands "${_script_subcommands_args[@]}"

    # Default behavior
    do_work
    }

    ## Runtime
    main "$@"
    _main "$@"
  2. @brianclements brianclements revised this gist Apr 29, 2020. 1 changed file with 25 additions and 5 deletions.
    30 changes: 25 additions & 5 deletions Bash Script.sh
    Original file line number Diff line number Diff line change
    @@ -6,12 +6,14 @@ A script for doing things."
    export script_mod_date='0000.00.00-00:00'
    export script_version='0.0.1'
    export script_requirements='none'
    export script_bash_debug=false
    ##----------------
    shopt -s extglob ## Needed for arg parsing

    ## Internal config
    export script_subcommands_args=()
    export script_min_args=1
    export script_max_args=1

    ## Script Config
    export working_dir=${working_dir:-"$PWD"}
    @@ -56,6 +58,12 @@ parseArgs() {
    usage_short
    exit 1
    fi
    if [[ ${#script_subcommands_args[@]} > $script_max_args ]]; then
    echo "Syntax error: only $script_max_args argument allowed."
    echo ""
    usage_short
    exit 1
    fi
    }

    parseSwitches() {
    @@ -73,7 +81,7 @@ parseSwitches() {
    exit 0
    ;;
    *)
    echo "Error: "${switches:0:1}" not a valid switch"
    echo "Error: \"${switches:0:1}\" not a valid switch"
    echo ""
    usage_short
    exit 1
    @@ -90,6 +98,9 @@ parseOptions() {
    local option_value=${option[@]:1}
    # Handle actions for individual options here
    case "${option_keyword}" in
    bash-debug)
    script_bash_debug=true
    ;;
    help)
    usage
    exit 0
    @@ -99,7 +110,7 @@ parseOptions() {
    exit 0
    ;;
    *)
    echo "Error: "${option_keyword}" not a valid option"
    echo "Error: \"${option_keyword}\" not a valid option"
    echo ""
    usage_short
    exit 1
    @@ -128,18 +139,21 @@ parseSubcommands() {

    ## Dialogs
    usage_cli=$(cat <<EOF
    Usage: ${script_name} <args>
    Usage: ${script_name} [<switches>...] [<option keyword>=<value>...] <subcommand> <subcommand args>
    ${script_short_desc}
    EOF
    )

    usage_args=$(cat <<EOF
    Switches/Options:
    -v|--version Version
    --bash-debug Show bash debug info for *most* of the non-template part
    of the script. It starts after the arguments are parsed.
    -h|--help Short|Full help
    -v|--version Version
    Subcommands
    work Werk it
    @@ -191,8 +205,14 @@ version() {

    ## Sequence
    main() {
    set -eo pipefail
    parseArgs "$@"
    # I realize this only effects the non-template part of the script; this is usually fine.
    # If you really want to debug the entire thing, then move `set -x` above `parseArgs "$@"`
    if $script_bash_debug; then
    set -x
    else
    set -eo pipefail
    fi
    parseSubcommands "${script_subcommands_args[@]}"

    # Default behavior
  3. @brianclements brianclements revised this gist May 26, 2017. 1 changed file with 50 additions and 20 deletions.
    70 changes: 50 additions & 20 deletions Bash Script.sh
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    #!/bin/bash
    ##----------------
    export script_name='Bash Script.sh'
    export script_name=$(basename -a "$0")
    export script_short_desc="
    A script for doing things."
    export script_mod_date='0000.00.00-00:00'
    @@ -9,9 +9,14 @@ export script_requirements='none'
    ##----------------
    shopt -s extglob ## Needed for arg parsing

    ## Config
    ## Internal config
    export script_subcommands_args=()
    export script_min_args=1

    ## Script Config
    export working_dir=${working_dir:-"$PWD"}
    export script_subcommands_args=("")

    # ----------------------------------------------------------------------------------------------

    ## Script
    do_work() {
    @@ -44,6 +49,13 @@ parseArgs() {
    args=("$@")
    done
    shopt -u extglob
    # Check for minimum number of arguments/subcommands beyond switches and options here.
    if [[ ${#script_subcommands_args[@]} < $script_min_args ]]; then
    echo "Syntax error: a minimum of $script_min_args arguments required."
    echo ""
    usage_short
    exit 1
    fi
    }

    parseSwitches() {
    @@ -53,7 +65,7 @@ parseSwitches() {
    # Handle actions for individual switches here
    case "${switches:0:1}" in
    h)
    usage
    usage_short
    exit 0
    ;;
    v)
    @@ -63,7 +75,7 @@ parseSwitches() {
    *)
    echo "Error: "${switches:0:1}" not a valid switch"
    echo ""
    usage
    usage_short
    exit 1
    ;;
    esac
    @@ -72,9 +84,7 @@ parseSwitches() {
    }

    parseOptions() {
    IFS='='
    local option=(${1})
    unset IFS
    local option=( $( IFS='='; echo ${1} ) )
    local option_keyword=${option[0]:2}
    # Get value of option if there is any
    local option_value=${option[@]:1}
    @@ -91,7 +101,7 @@ parseOptions() {
    *)
    echo "Error: "${option_keyword}" not a valid option"
    echo ""
    usage
    usage_short
    exit 1
    ;;
    esac
    @@ -117,10 +127,38 @@ parseSubcommands() {
    }

    ## Dialogs
    usage_cli=$(cat <<EOF
    Usage: ${script_name} <args>
    ${script_short_desc}
    EOF
    )

    usage_args=$(cat <<EOF
    Switches/Options:
    -v|--version Version
    -h|--help Short|Full help
    Subcommands
    work Werk it
    EOF
    )

    usage_short() {
    cat <<EOF
    ${usage_cli}
    ${usage_args}
    Run '${script_name} --help' for the full help documentation.
    EOF
    }

    usage() {
    cat <<EOF
    Usage: "${script_name}" <args>
    ${script_short_desc}
    ${usage_cli}
    Switches can be combined, or used individually, in any order. Options must
    follow the format --option="something here" and not have spaces in between
    @@ -133,15 +171,7 @@ By default:
    "exit" is declared in any of the 'case' statements. This is the current
    behavior but can be easily changed.
    Switches/Options:
    -v|--version Version
    -h|--help This help
    Subcommands
    work Werk it
    ${usage_args}
    Requirements:
  4. @brianclements brianclements revised this gist Sep 11, 2016. 1 changed file with 40 additions and 13 deletions.
    53 changes: 40 additions & 13 deletions Bash Script.sh
    Original file line number Diff line number Diff line change
    @@ -11,13 +11,41 @@ shopt -s extglob ## Needed for arg parsing

    ## Config
    export working_dir=${working_dir:-"$PWD"}
    export script_subcommands_args=("")

    ## Script
    do_work() {
    echo "doing work in ${working_dir}"
    }

    ## Args
    parseArgs() {
    local args=("$@")
    while (( "${#args}" )); do
    case "$1" in
    -@([a-z|A-Z]*))
    # Switches
    parseSwitches "$1"
    ;;
    --*)
    # Options
    parseOptions "$1"
    ;;
    *)
    # Subcommands args stored as an array for later. For more
    # complicated scripts, sometimes we need to act on the
    # switches/options or source configuration first before we run
    # the subcommands.
    script_subcommands_args=("$@")
    break
    ;;
    esac
    shift
    args=("$@")
    done
    shopt -u extglob
    }

    parseSwitches() {
    local switches="$1"
    switches="${switches:1}"
    @@ -69,29 +97,23 @@ parseOptions() {
    esac
    }

    parseArgs() {
    parseSubcommands() {
    local args=("$@")
    while (( "${#args}" )); do
    case "$1" in
    -@([a-z|A-Z]*))
    # Switches
    parseSwitches "$1"
    ;;
    --*)
    # Options
    parseOptions "$1"
    work)
    echo "Args passed to work command: ${args[@]:1}"
    break
    ;;
    *)
    # Anything not a switch or option
    echo "Error: "$1" not a valid argument"
    echo ""
    echo "Error: "$1" not a valid subcommand"
    usage
    exit 1
    ;;
    esac
    shift
    args=("$@")
    done
    shopt -u extglob
    }

    ## Dialogs
    @@ -111,12 +133,16 @@ By default:
    "exit" is declared in any of the 'case' statements. This is the current
    behavior but can be easily changed.
    Options:
    Switches/Options:
    -v|--version Version
    -h|--help This help
    Subcommands
    work Werk it
    Requirements:
    ${script_requirements}
    @@ -137,6 +163,7 @@ version() {
    main() {
    set -eo pipefail
    parseArgs "$@"
    parseSubcommands "${script_subcommands_args[@]}"

    # Default behavior
    do_work
  5. @brianclements brianclements revised this gist Aug 11, 2016. 1 changed file with 9 additions and 5 deletions.
    14 changes: 9 additions & 5 deletions Bash Script.sh
    Original file line number Diff line number Diff line change
    @@ -44,10 +44,14 @@ parseSwitches() {
    }

    parseOptions() {
    local option="$1"
    option="${option:2}"
    IFS='='
    local option=(${1})
    unset IFS
    local option_keyword=${option[0]:2}
    # Get value of option if there is any
    local option_value=${option[@]:1}
    # Handle actions for individual options here
    case "${option}" in
    case "${option_keyword}" in
    help)
    usage
    exit 0
    @@ -57,7 +61,7 @@ parseOptions() {
    exit 0
    ;;
    *)
    echo "Error: "${option}" not a valid option"
    echo "Error: "${option_keyword}" not a valid option"
    echo ""
    usage
    exit 1
    @@ -109,7 +113,7 @@ By default:
    Options:
    -v|--version version
    -v|--version Version
    -h|--help This help
  6. @brianclements brianclements created this gist Jul 17, 2016.
    142 changes: 142 additions & 0 deletions Bash Script.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,142 @@
    #!/bin/bash
    ##----------------
    export script_name='Bash Script.sh'
    export script_short_desc="
    A script for doing things."
    export script_mod_date='0000.00.00-00:00'
    export script_version='0.0.1'
    export script_requirements='none'
    ##----------------
    shopt -s extglob ## Needed for arg parsing

    ## Config
    export working_dir=${working_dir:-"$PWD"}

    ## Script
    do_work() {
    echo "doing work in ${working_dir}"
    }

    ## Args
    parseSwitches() {
    local switches="$1"
    switches="${switches:1}"
    while (( "${#switches}" )); do
    # Handle actions for individual switches here
    case "${switches:0:1}" in
    h)
    usage
    exit 0
    ;;
    v)
    version
    exit 0
    ;;
    *)
    echo "Error: "${switches:0:1}" not a valid switch"
    echo ""
    usage
    exit 1
    ;;
    esac
    switches="${switches:1}"
    done
    }

    parseOptions() {
    local option="$1"
    option="${option:2}"
    # Handle actions for individual options here
    case "${option}" in
    help)
    usage
    exit 0
    ;;
    version)
    version
    exit 0
    ;;
    *)
    echo "Error: "${option}" not a valid option"
    echo ""
    usage
    exit 1
    ;;
    esac
    }

    parseArgs() {
    local args=("$@")
    while (( "${#args}" )); do
    case "$1" in
    -@([a-z|A-Z]*))
    # Switches
    parseSwitches "$1"
    ;;
    --*)
    # Options
    parseOptions "$1"
    ;;
    *)
    # Anything not a switch or option
    echo "Error: "$1" not a valid argument"
    echo ""
    usage
    ;;
    esac
    shift
    args=("$@")
    done
    shopt -u extglob
    }

    ## Dialogs
    usage() {
    cat <<EOF
    Usage: "${script_name}" <args>
    ${script_short_desc}
    Switches can be combined, or used individually, in any order. Options must
    follow the format --option="something here" and not have spaces in between
    the option keyword and it's value.
    By default:
    - Any arguments that aren't switches or options are treated as erroneous, but
    they could potentially be main arguments subcommands.
    - The script processes all switches and all options, but stops only if
    "exit" is declared in any of the 'case' statements. This is the current
    behavior but can be easily changed.
    Options:
    -v|--version version
    -h|--help This help
    Requirements:
    ${script_requirements}
    Version:
    ${script_name} version: ${script_version}
    Last modifed on: ${script_mod_date}
    EOF
    }

    version() {
    echo "${script_name} version: ${script_version}"
    echo "Last modifed on: ${script_mod_date}"
    }

    ## Sequence
    main() {
    set -eo pipefail
    parseArgs "$@"

    # Default behavior
    do_work
    }

    ## Runtime
    main "$@"