How to deal with end of options — in getopts

I use getopts to parse arguments in bash scripts as

while getopts ":hd:" opt; do
  case $opt in
    d ) echo "directory = $OPTARG"; mydir="$OPTARG"; shift $((OPTIND-1)); OPTIND=1 ;;
    h ) helptext
      graceful_exit ;;
    * ) usage
      clean_up
      exit 1
  esac
done

exeparams="$*"

exeparams will hold any unparsed options/arguments. Since I want to use exeparams to hold options for a command to be executed within the script (which can overlap with the scripts own options), I want to use — to end the options passed to the script. If I pass e.g.

myscript -d myscriptparam -- -d internalparam

exeparams will hold

-- -d internalparam

I now want to remove the leading -- to pass these arguments to the internal command. Is there an elegant way to do this or can I obtain a string which holds just the remainder without -- from getopts?

Asked By: highsciguy

||

Use the built-in shift. First, do the normal getopts for your script. Once that loop completes,

shift "$((OPTIND - 1))"

will shift out all the already processed options.

From there, you’ll have to finish processing the non-option arguments, if any, to the first part of the script (before the --). Once you encounter the --, shift it out until only the latter portion remains (the -d internalparam part that comes after --). One way to do this (using bash syntax):

while [[ $# -gt 0 ]]; do
    # process next argument
    case $1 in
    foo) # process foo
    ;;
    --) shift; break;; # found '--', discard it and exit loop
    *) # handle unrecognized argument
    ;;
    esac
    # not '--', so discard the argument and continue
    shift
done

Finally, only the second set of options / arguments remain, which you can pass on. Do NOT use $* to pass the remaining parameters to another command. Use "$@" instead, which preserves the original word splitting.

external_command "$@"
Answered By: jw013

How about:

# ... getopts processing ...

[[ $1 = "--" ]] && shift
exeparams=("$@")

Note, you should use an array to hold the parameters. That will properly handle any arguments containing whitespace. Dereference the array with "${exeparams[@]}"

Answered By: glenn jackman
Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.