Skip to content

Instantly share code, notes, and snippets.

@adamhotep
Last active February 26, 2026 14:25
Show Gist options
  • Select an option

  • Save adamhotep/895cebf290e95e613c006afbffef09d7 to your computer and use it in GitHub Desktop.

Select an option

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))
@jbrubake
Copy link

If you pass a long-only option that requires an argument, the above code only works if you pass it like --option=arg. It does not work without the =. I got it to work like this but is there a better way:

    reset=true stopped="" grab=
    for option in "$@"; do
    ...    
        # If $grab is set then we have an option waiting for an argument
        if [ -n "$grab" ]; then
            optarg=$opt # $opt holds the needed argument
            opt=$grab   # recheck the previous option
            unset grab  # unset the flag
        fi

        case "$stopped$opt" in
           --long-only)
                # $optarg is normally only set if we passed --opt=arg. If we passed
                # '--opt arg' without the '=' we need to grab the next value of $opt
                # as our argument
                #
                # $optarg is set so we can process the option
                if [ -n "$optarg" ]; then
                    echo "Got --long-only=$optarg"
                # $optarg is not set so we set a flag to the name of this option so
                # the next time through the loop we can match this block again
                else
                    grab=--long-only
                fi
                ;;
    ...

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