I'm looking for a way to do option parsing in a Bash script (allowing for both short and long arguments as getopt does) that stops parsing at the first unrecognized argument, places a -- before that first unrecognized argument, and then copies the remaining arguments to the output string.For example, here's the behavior that I want:% OPTIONS=(-u name1 --username=name2 -x a -u b c)% getopt -o u: -l username: -n programname -- ${OPTIONS[@]}-u 'name1' --username 'name2' -- -x 'a' -u 'b' 'c'%The utility getopt does not work this way, and instead emits the following:programname: invalid option -- 'x'-u 'name1' --username 'name2' -u 'b' -- 'a' 'c'Note that I do not want arguments that follow an unrecognized option to be reordered as if they were recognized, as is demonstrated above with the second -u option. I'm hoping that someone will have a solution that will give the results I demonstrate in the first code block above.  Any ideas?Environment: bash 4.2.46(1), CentOS 7.2 @3.10.0-327.36.1.el7.x86_64.Requirements: CentOS 7.2 Minimal with no additional software to be installed with all code written in a Bash script. The options passed to the options parser are not required to include -- in them (that is, the termination of parsing should be automatic).
How can options be parsed in a Bash script, leaving unrecognized options after the --?
bash;shell script;getopts
The solution to this problem requires something other than getopt because getopt rearranges options that it finds that do match the option specification and terminates on unrecognized options. The Bash built-in getopts comes to the rescue, but needs to be able to handle long options. In a post by Arvid Requate and TomRoche, there is a trick that allows getopts to handle long options: use - as an option specification and use a leading colon in the options specification to silence error reporting. Their solution, however, would require that code be duplicated for handling short and long options.Here is a solution that I've tested that meets all of my requirements and also does not duplicate handling for short and long options. For clarity and completeness, I've changed username to set and added toggle to demonstrate options not taking values.parse.sh#!/bin/bashOptions=($@)while getopts :s:-: OptChar ${Options[@]}; do   case $OptChar in    -)   case $OPTARG in         set|set=*)            if [[ $OPTARG =~ ^set= ]] ; then               Value=${Options[$OPTIND-2]#*=}            else               Value=${Options[$OPTIND-1]}               ((OPTIND++))            fi            echo Parsed: --$OPTARG, value: '$Value'            ;;         toggle)            echo Parsed: --$OPTARG;;         *) ((OPTIND--)); break;;         esac         ;;   # Redirect short arguments to long arguments   s)    ((OPTIND-=2)); Options[OPTIND-1]=--set;;   t)    ((OPTIND--)); Options[OPTIND-1]=--toggle;;   *)    ((OPTIND--)); break;;   esacdoneOptions=( ${Options[@]:$OPTIND-1} )echo REMAINING Options: ${Options[@]}and here is my test code:% ./parse.sh --set=a  -s b --set= --set c --unknown -s d --set eParsed: --set=a, value: 'a'Parsed: --set, value: 'b'Parsed: --set=, value: ''Parsed: --set, value: 'c'REMAINING Options: --unknown -s d --set e%% ./parse.sh -s a -x -s bParsed: --set, value: 'a'REMAINING Options: -x -s b%