I don't see why you couldn't simulate long options by treating - as a short option requiring an argument:
$ cat /tmp/foo while getopts :aq:-: opt; do case $opt in a) echo option -a;; q) echo option -q with value "$OPTARG";; -) case $OPTARG in abc) echo option --abc;; def=*) echo option --def with value "${OPTARG#*=}";; *) echo >&2 "unknown option --$OPTARG";; esac;; :) echo >&2 "-$OPTARG needs an argument";; *) echo >&2 "unknown option -$OPTARG";; esac done shift "$((OPTIND - 1))" echo argv: "$@" $ sh /tmp/foo -a -qt --abc --def=ghi -- foo bar option -a option -q with value t option --abc option --def with value ghi argv: foo bar
If you want to make a list of arguments (eg. to call another command with it), and your shell doesn't support arrays (eg. debian's or busybox's /bin/sh), you can use the following trick, which will pass to eval a list of argument indexes instead of actual strings; that will avoid any IFS splitting/globbing/whitespace annoyances:
$ cat /tmp/foo # handle -a and -qval # call another command with any long options and non-option arguments av= while getopts :aq:-: opt; do case $opt in a) echo option -a;; q) echo option -q with value "'$OPTARG'";; -) av="$av \"\${$((OPTIND-1))}\"" ;; # pass long options unchanged :) echo >&2 "-$OPTARG needs an argument";; *) echo >&2 "unknown option -$OPTARG";; esac done i=$OPTIND; while [ "$i" -le "$#" ]; do av="$av \"\${$i}\"" i=$((i + 1)); done print_its_args(){ for a; do printf ' {%s}' "$a"; done; echo; } echo "print_its_args $av" eval "print_its_args $av"
Then:
$ sh /tmp/foo -aqval --foo='a ** b' --abc -- '(moo)' option -a option -q with value 'val' print_its_args "$2" "$3" "$5" {--foo=a ** b} {--abc} {(moo)}
This trick could be used in other situations; but this is a case where a simpler solution like set -- "$@" arg to push args into $@ cannot be used, because modifying $@ inside the getopts loop cannot be done in a portable way.
my_utility, but it requires keeping in mind special cases where the getopts parameter must handle options with values.shutil.copy2()for the former andsubprocess.check_call([...])andsubprocess.check_output([...])for the latter. In many cases you can still keep these as one-liners. And the language expressiveness you gain for the rest of the script is definitely worth it!