1

I have an array of options and their arguments:

ARGS=('-a' '-c' 'red' 'orange' '--verbose' '-p' 'apple' 'banana')

I need to extract arguments for the option -c and get a list of the rest:

echo "${COLORS[@]}" # returns: red orange
echo "${OPTIONS[@]}" # returns: -a --verbose -p apple banana

I have managed to get a list of colors using getopts (probably not the best approach), but I didn't find a way to extract the rest of the options.

COLORS=()

set_colors() {
  while getopts "p:" option 2>/dev/null; do
    case ${option} in
      p)
        COLORS+=("$OPTARG")
        while [[ "$OPTIND" -le "$#" ]] && [[ "${!OPTIND:0:1}" != "-" ]]; do
          COLORS+=("${!OPTIND}")
          ((OPTIND++))
        done
        ;;
      *) ;;
    esac
  done
}

set_colors "${ARGS[@]}"
4
  • 2
    To be compatible with other tools, I propose to make your tool accept the command line options as -a -c red -c orange --verbose -p apply -p banana - ie. the -c flag is cumulative and needs to be specified for each color. This will make parsing arguments easier and more consistent for a small inconvenience. Commented Dec 14, 2019 at 20:27
  • As an aside, all-caps is used for variables that modify or reflect behavior of the shell itself and POSIX-defined tools; the standard recommends using names with at least one lower-case character in your own software to avoid inadvertently modifying behavior of standard-defined tools. (Read the linked specification keeping in mind that shell variables and environment variables share a single namespace -- modifying the former change the latter implicitly when the names match). Commented Dec 14, 2019 at 20:40
  • ...and btw, I strongly agree with @KamilCuk's recommendation above. It's a widely-used convention for good reason. Commented Dec 14, 2019 at 20:50
  • Thank you for the suggestions. I'll follow all of them Commented Dec 14, 2019 at 22:28

1 Answer 1

1

I used the variable $in_colors as a flag when walking over the options and distributing them into two arrays.

#! /bin/bash
ARGS=('-a' '-c' 'red' 'orange' '--verbose' '-p' 'apple' 'banana')

in_colors=0
for arg in "${ARGS[@]}" ; do

    if [[ $arg == '-c' ]] ; then
        in_colors=1
    elif [[ $arg == -* ]] ; then
        in_colors=0
    fi

    if ((in_colors)) ; then
        colors+=("$arg")
    else
        opts+=("$arg")
    fi
    shift
done
echo "Colors: ${colors[@]}"
echo "Options: ${opts[@]}"
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.