Skip to content

Instantly share code, notes, and snippets.

@dnschneid
Last active August 29, 2015 14:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dnschneid/a6d3b9628c2f2baab540 to your computer and use it in GitHub Desktop.
Save dnschneid/a6d3b9628c2f2baab540 to your computer and use it in GitHub Desktop.
getopts positional parameter reordering hack
#!/bin/sh -e
set -e
# Works mostly like built-in getopts but silently coalesces positional arguments.
# Does not take parameters. Set getopts_string prior to calling.
# Sets getopts_var and getopts_arg.
# $@ will be left with the positional arguments, so you should NOT shift at all.
# In bash, enables alias expansion until arguments are done being processed.
shopt -q -s expand_aliases 2>/dev/null || true
getopts_npos=0
getopts_dashdash=''
alias getopts_nextarg='getopts_ret=1
while [ "$#" -gt "$getopts_npos" ]; do
if [ -z "$getopts_dashdash" ] && getopts "$getopts_string" getopts_var; then
if [ "$(($#+1-OPTIND))" -lt "$getopts_npos" ]; then
# Bad parameter usage ate a positional argument.
# Generate the proper error message by abusing getopts.
set -- "-$getopts_var"
getopts "$getopts_var:" getopts_var
shift
fi
getopts_arg="$OPTARG"
getopts_ret=0
# Avoid -- confusion by shifting if OPTARG is set
if [ -n "$OPTARG" ]; then
shift "$((OPTIND-1))"
OPTIND=1
fi
break
fi
# Do not let getopts consume a --
if [ "$OPTIND" -gt 1 ]; then
shift "$((OPTIND-2))"
if [ "$1" != "--" ]; then
shift
fi
fi
OPTIND=1
if [ -z "$getopts_dashdash" -a "$1" = "--" ]; then
# Still need to loop through to fix the ordering
getopts_dashdash=y
else
set -- "$@" "$1"
getopts_npos="$((getopts_npos+1))"
fi
shift
done
if [ "$getopts_ret" = 1 ]; then
shopt -q -u expand_aliases 2>/dev/null || true
fi
[ "$getopts_ret" = 0 ]'
# Test application.
# Try running this script using some of these parameters, positionals, and --'s
# Try using -- after a parameter that takes -- as an argument
# Try adding a trailing parameter
# Try combining parameters together into one multi-switch
getopts_string='a:bdef:k:m:M:n:p:P:r:s:t:T:uUV'
while getopts_nextarg; do
echo "-$getopts_var $getopts_arg"
done
echo "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment