Skip to content

Instantly share code, notes, and snippets.

@adamhotep
Last active November 29, 2023 23:22
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save adamhotep/895cebf290e95e613c006afbffef09d7 to your computer and use it in GitHub Desktop.
Save adamhotep/895cebf290e95e613c006afbffef09d7 to your computer and use it in GitHub Desktop.
POSIX shell: support long options by converting them to short options
# a refinement of https://stackoverflow.com/a/5255468/519360
# see also my non-translating version at https://stackoverflow.com/a/28466267/519360
# translate long options to short
reset=true stopped=""
for opt in "$@"; do
if [ -n "$reset" ]; then
unset reset
set -- # reset the "$@" array so we can rebuild it
fi
case "$opt" in # --option=argument -> opt='--option' optarg='argument'
--?*=* ) optarg="${opt#*=}" opt="${opt%%=*}" ;;
* ) unset optarg ;;
esac
case "$stopped$opt" in
-- ) stopped=true; set -- "$@" -- ;;
--help ) set -- "$@" -h ;;
--verbose ) set -- "$@" -v ;;
--config ) set -- "$@" -c ${optarg+"$optarg"} ;;
--long-only ) DEMO_LONG_ONLY_FLAG=true ;;
# pass anything else through, including spaced arguments
* ) set -- "$@" "$opt" ;;
esac
done
# now we can process with getopt
while getopts ":hvc:" opt; do
case $opt in
h ) usage ;;
v ) VERBOSE=true ;;
c ) source $OPTARG ;;
\? ) usage ;;
: )
echo "option -$OPTARG requires an argument"
usage
;;
esac
done
shift $((OPTIND-1))
@adamhotep
Copy link
Author

Aside from needing a preprocessing loop, this approach has a flaw in that it loses the long option name; if you trigger that : clause (meaning you've forgotten an option's argument), the complaint uses $opt (which getopts has converted to $OPTARG), e.g. -c in place of --config.

Working around that is only a little ugly: Add "--$opt" after each set -- "$@" in the second case of the for loop excluding the * clause. Before that final clause, add a new -* ) set -- "$@" "--$opt" "$opt" ;; clause. Add -: to the getopts optstring. Add - ) param="$OPTARG" ;; to the getopts loop's case stanza, and then refer to $param instead of -$OPTARG.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment