'Bash - Best way to have helpFunction & default parameter values

After a lot of read, SO or others, I'm really wondering about the best / cleanest way to have a bash script with parameters, optionals with default values.

Here is my script for now:

#!/bin/bash

helpFunction()
{
   echo ""
   echo "Usage: $0 --reload --mode=[single|cluster]"
   echo -e  "\t--reload Reload the database : fixtures & schema"
   echo -e  "\t--mode Mode of build : single or cluster"
   exit 1
}

while [[ "$#" -gt 0 ]]; do
    case $1 in
        -h|--help) helpFunction; shift ;;
        -r|--reload) reload=true; shift ;;
        -m|--mode) mode="single"; shift ;;
        # ... (same format for other required arguments)
        *) echo "Unknown parameter passed: $1" ;;
    esac
    shift
done

./bin/sh/tools/build.sh -e local -m $mode -p local

For now, the $mode variable seems to not be set if I don't set it, how can I have a default value for this variable ? (default is single)

What I want is the user to call the script like (reload is true, mode is cluster):

bin/script.sh -r --mode=cluster 

Or by default (reload is false, mode is single):

bin/script.sh

Is this the good way to wait for parameters ? I read other ways, but no real explanations.

Thanks.



Solution 1:[1]

If you set the mode beforehand, that will be its default. If you want parameter with assignment, you need to grab $2 and shift twice.

mode="single"
while [[ "$#" -gt 0 ]]; do
    case $1 in
        -h|--help) helpFunction; shift ;;
        -r|--reload) reload=true; shift ;;
        -m|--mode) mode="$2"; shift; shift ;;
        # ... (same format for other required arguments)
        *) echo "Unknown parameter passed: $1" ;;
    esac
    shift
done

I think it's also good to restore the positional arguments. Since you may want to use them, but that depends on your script.

mode="single"
reload="false"

POSITIONAL=()
while [[ "$#" -gt 0 ]]; do
  case $1 in
  -h | --help)
    helpFunction
    shift
    ;;
  -r | --reload)
    reload=true
    shift
    ;;
  -m | --mode)
    mode="$2"
    shift
    shift
    ;;
  *)
    POSITIONAL+=("$1")
    shift
    ;;
  esac
done
set -- "${POSITIONAL[@]}"

COMMAND="$1"

Then you could invoke a function that is called like the $COMMAND and pass the rest of the params with $@, and shift again and set the subcommand to $1. You can do this infinitely to get a chain of (sub)commands.

You can still check if a valid command was provided before you try to call the $COMMAND.

COMMAND_LIST="add issue revoke"

case $COMMAND_LIST in
*"$COMMAND"*)
  "$COMMAND" "$@"
  ;;
*)
  helpFunction
  echo "ERROR: Unknown command: $COMMAND"
  exit 1
  ;;
esac

But that is of course only if your script supports commands/subcommands. Otherwise, it makes sense to error right away like you did, if there is an unknown parameter.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1