Context
I'm trying to write a decent bash parser using separate files and functions for:
- argument parsing (e.g. determining what to do)
- parsed argument processing (e.g. doing those things)
- printing the CLI usage.
However, when I try to pass the "POSITIONAL_ARGS" into the parse_args() {, the arguments don't seem to arrive.
Example:
Suppose I have the following main.sh file in directory: /src:
#!/bin/bash
POSITIONAL_ARGS=()
# source arg_parser.sh
source src/arg_parser/arg_parser.sh
source src/arg_parser/print_usage.sh
# print the usage if no arguments are given
[ $# -eq 0 ] && { print_usage; exit 1; }
echo "POSITIONAL_ARGS=$POSITIONAL_ARGS"
parse_args "$POSITIONAL_ARGS"
And the following arg_parser.sh file in: src/arg_parser/arg_parser.sh:
#!/bin/bash
parse_args() {
  local positional_args="$1"
  # Specify default argument values.
  local apply_certs_flag='false'
  local check_http_flag='false'
  local check_https_flag='false'
  local generate_certs_flag='false'
  local project_name_flag='false'
  local port_flag='false'
  while [[ $# -gt 0 ]]; do
    echo "dollar1=$1"
    echo "positional_args=$positional_args"
    echo "dollar hashtag=$#"
    case $1 in
      -a|--apply-certs)
        apply_certs_flag='true'
        shift # past argument
        ;;
      -ch|--check-http)
        check_http_flag='true'
        shift # past argument
        ;;
      -cs|--check-https)
        check_https_flag='true'
        shift # past argument
        ;;
      -g|--generate-certs)
        generate_certs_flag='true'
        shift # past argument
        ;;
      -n|--project-name)
        project_name_flag='true'
        project_name="$2"
        assert_is_non_empty_string "${project_name}"
        shift # past argument
        shift
        ;;
      -p|--port)
        port_flag='true'
        port="$2"
        assert_is_non_empty_string "${project_name}"
        shift # past argument
        shift
        ;;
      -*)
        echo "Unknown option $1"
        print_usage
        exit 1
        ;;
    esac
  done
  set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters
}
Expected output
When I run ./src/main.sh -a, I would expect the output:
echo "POSITIONAL_ARGS=-a
dollar1=-a
positional_args=-a
dollar_hashtag=1
dollar1=-a
positional_args=-a
dollar_hashtag=0
Output
However, instead of parsing/eating/shifting the arguments, the actual output is an infinite loop:
dollar1=
positional_args=
dollar hashtag=1
dollar1=
positional_args=
dollar hashtag=1
dollar1=
positional_args=
dollar hashtag=1
.... etc.
Question
How could I pass the arguments from the CLI from src/main.sh into the parse_args() function in the file src/arg_parser/arg_parser.sh such that they can be parsed?
Notes
I used to have
 -p|--prereq)
      prerequistes_only_flag='true'
      shift # past argument
      ;;
    -*|--*)
      echo "Unknown option $1"
      print_usage
      exit 1
      ;;
    *)
      POSITIONAL_ARGS+=("$1") # save positional arg
      shift # past argument
      ;;
  esac
however, shellcheck says the --*) will never be reached because of the -*|.
Hypothesis
I think at least one error may be that I, in the original question, treated POSITIONAL_ARGS as a string instead of an array. However, shellcheck tells me it is an array:
In src/main.sh line 26:
echo "POSITIONAL_ARGS=$POSITIONAL_ARGS"
                      ^--------------^ SC2128 (warning): Expanding an array without an index only gives the first element.
