This is a little tutorial that I found in my search to learn how to use getopt (mind: not getopts, which is a completely different thing). I want to share it here because I find it refreshingly to the point. Just the main code block already tells almost the whole story:

#!/bin/bash
# Set some default values:
ALPHA=unset
BETA=unset
CHARLIE=unset
DELTA=unset

usage()
{
  echo "Usage: alphabet [ -a | --alpha ] [ -b | --beta ]
                        [ -c | --charlie CHARLIE ] 
                        [ -d | --delta   DELTA   ] filename(s)"
  exit 2
}

PARSED_ARGUMENTS=$(getopt -a -n alphabet -o abc:d: --long alpha,bravo,charlie:,delta: -- "$@")
VALID_ARGUMENTS=$?
if [ "$VALID_ARGUMENTS" != "0" ]; then
  usage
fi

echo "PARSED_ARGUMENTS is $PARSED_ARGUMENTS"
eval set -- "$PARSED_ARGUMENTS"
while :
do
  case "$1" in
    -a | --alpha)   ALPHA=1      ; shift   ;;
    -b | --beta)    BETA=1       ; shift   ;;
    -c | --charlie) CHARLIE="$2" ; shift 2 ;;
    -d | --delta)   DELTA="$2"   ; shift 2 ;;
    # -- means the end of the arguments; drop this, and break out of the while loop
    --) shift; break ;;
    # If invalid options were passed, then getopt should have reported an error,
    # which we checked as VALID_ARGUMENTS when getopt was called...
    *) echo "Unexpected option: $1 - this should not happen."
       usage ;;
  esac
done

echo "ALPHA   : $ALPHA"
echo "BETA    : $BETA "
echo "CHARLIE : $CHARLIE"
echo "DELTA   : $DELTA"
echo "Parameters remaining are: $@"

Just be sure to correct the inadvertent mixing of beta and bravo.

  • FizzyOrange@programming.dev
    link
    fedilink
    English
    arrow-up
    5
    ·
    5 days ago

    If you find yourself needing this, the correct thing to do is to stop writing that shell scripts and switch to a proper language.

    • tjhowse@lemmy.world
      link
      fedilink
      English
      arrow-up
      9
      ·
      5 days ago

      While I agree with you, I think it’s a bit unkind to reply in this way. Sometimes bash is all you have, and it’s interesting to learn about tools even if you’re unlikely to use them.

  • MonkderVierte@lemmy.zip
    link
    fedilink
    English
    arrow-up
    2
    ·
    edit-2
    5 days ago

    I’ve got one from stackoverflow i tidied up and expanded, that handles long options as well, but you really should learn Python instead. Talking from experience; even with a state machine approach and helpful little functions and debug helpers, juggling so much input is hard in shell.

    Well, you’re warned now and here it is:

    tool_name="tool"
    tool_descr="tool does tool things"
    
    printhelp() {
    	printf '%s\nSyntax: %s [options]...\n%s\n' "$tool_descr" "$tool_name" "$tool_args"
    }
    bool() { [ -n "$OPTARG" ] && error "--${OPT} accepts no parameters" 7; }
    # cli-parser
    #--------------------------------------------------------------
    tool_args='
      -s, --stuff          stuff to do
      -o, --other          other stuff to do
    
      -V, --verbose        Tell what i do
      -v, --version        Print version of this tool and exit
      -h, --help           This help text
    '
    while getopts "vVhbs:o:-:" OPT; do
    	# support long options: https://stackoverflow.com/a/28466267/519360
    	if [ "$OPT" = "-" ]; then           # long option: reformulate OPT and OPTARG
    		OPT="${OPTARG%%=*}"             # extract long option name
    		OPTARG="${OPTARG#"$OPT"}"       # extract long option argument (may be empty)
    		OPTARG="${OPTARG#=}"            # if long option argument, remove assigning `=`
    	fi
    	case "$OPT" in
    		s | stuff )       arg_stuff="$OPTARG"
    	;;  o | other )       arg_other="$OPTARG"
    	;;  V | verbose )     bool; verbose=true
    	;;  v | version )     bool; printversion; exit 0
    	;;  h | help )        printhelp; exit 0
    	;;  ??* )             error "Illegal option --$OPT" 22  # bad long option
    	;;  : )               exit 2                            # missing parameter (error reported via getopts)
    	;;  ? )               exit 22                           # bad short option (error reported via getopts)
    	esac
    done
    [ $OPTIND -eq 1 ] && \
    if { [ -e "$1" ] && [ $# -gt 0 ]; }                         # check for lazy file argument
    	then lazy_arg="$1"
    	else printhelp && exit 0
    fi
    shift $((OPTIND-1)) # remove parsed options and args from $@ list
    
  • sjohannes@programming.dev
    link
    fedilink
    English
    arrow-up
    1
    ·
    edit-2
    4 days ago

    The article mentions “GNU getopt” but as far as I know GNU doesn’t have a getopt utility; the version on most Linux OSes comes from util-linux. (Perhaps the author is confusing it with the C function with the same name.)

    Note that other getopt implementations have different features and some are simply broken. For example, BSD getopt doesn’t support long options and comes with this known bug:

    Arguments containing whitespace or embedded shell metacharacters generally will not survive intact; this looks easy to fix but isn’t.

    For cross-platform scripts it’s probably best to use the getopts shell builtin instead, the downside being it only supports fairly basic (POSIX) syntax even on Bash.

  • SubArcticTundra@lemmy.ml
    link
    fedilink
    English
    arrow-up
    2
    ·
    edit-2
    5 days ago

    I still think my favorite shell, NuShell, handles this the best:

    def alphabet [
        --alpha (-a)
        --charlie (-c): string    # comments on these lines are parsed and used for automatically generated --help flag
        --delta: int
        ...filenames: string
    ] { echo \$alpha }"
    

    So much less boilerplate