2

I would like to put my getopt call into a function so I can make my script a bit more tidy. I've read a few guides Using getopts inside a Bash function but they seem to be for getopts not getopt and cannot get my head round it.

I have the following getopt call at the start of my script

#-------------------------------------------------------------------------------
# Main
#-------------------------------------------------------------------------------
getopt_results=$( getopt -s bash -o e:h --long ENVIRONMENT:,HELP:: -- "$@" )

if test $? != 0
then
    echo "Failed to parse command line unrecognized option" >&2
    Usage
    exit 1
fi

eval set -- "$getopt_results"

while true
do
  case "$1" in
      -e | --ENVIRONMENT)
          ENVIRONMENT="$2"
          if [ ! -f "../properties/static/build_static.${ENVIRONMENT}.properties" -o ! -f "../properties/dynamic/build_dynamic.${ENVIRONMENT}.properties" ]; then
            echo "ERROR: Unable to open properties file for ${ENVIRONMENT}"
            echo "Please check they exist or supply a Correct Environment name"
            Usage
            exit 1
          else
            declare -A props
            readpropsfile "../properties/dynamic/dynamic.${ENVIRONMENT}.properties"
            readpropsfile "../properties/static/static.${ENVIRONMENT}.properties"
          fi
          shift 2
          ;;
      -h | --HELP)
          Usage
          exit 1
     ;;
      --)
         shift
         break
         ;;
      *)
         echo "$0: unparseable option $1"
         Usage
         exit 1
         ;;
  esac
done

when I put the whole lot in function , say called parse_command_line () and call it with parse_command_line "$@" my script dies because it cannot work out the parameters it was called with. I have tried making OPTIND local as per some of the guides. Any advice? Thanks.

AndyM
  • 562
  • 4
  • 22
  • 2
    Show the *exact* function you are writing, and the *exact* error or result you are getting. – chepner Dec 04 '17 at 18:15
  • 1
    See [BashFAQ #35](http://mywiki.wooledge.org/BashFAQ/035#getopts), particularly the warning (near the bottom) to **never use `getopt`**. – Charles Duffy Dec 04 '17 at 18:26
  • 1
    Note that `set -- arg arg arg` done in a function will set the **function**'s positional parameters, not the "global" positional parameters. You'll need to do `getopt_results=$(parse_command_line "$@"); eval set -- "$getopt_results"` and then you're not much tidier than you have now. – glenn jackman Dec 04 '17 at 18:27
  • Thanks I'm now thinking it to do with the loading of the props file , its seems to be no longer global after I've put it in a function. As for the don't use getopt , so much conflicting info - I read a post saying the opposite. – AndyM Dec 04 '17 at 18:56
  • @CharlesDuffy this post says different https://stackoverflow.com/questions/78497/design-patterns-or-best-practices-for-shell-scripts/739034#739034 – AndyM Dec 04 '17 at 21:53
  • 1
    @AndyM, ...and that post's using tons of bad practices, like the non-POSIX-compatible `function` keyword, the incompatible `==` comparison operator for `test`, backticks for command substitution (which don't nest well and change the behavior of backslashes within them), etc (including all-caps variable names, which POSIX explicitly specifies are used for variables with meaning to the OS and shell, while lowercase variables are reserved for application use). The wiki I linked above is maintained by and reflects consensus of the irc.freenode.org #bash channel. – Charles Duffy Dec 04 '17 at 21:56
  • 1
    @AndyM, ...btw, the other resource I strongly recommend is [the bash-hackers' wiki](http://wiki.bash-hackers.org/scripting/posparams), which provides [a `getopts` tutorial](http://wiki.bash-hackers.org/howto/getopts_tutorial), likewise arguing *against* `getopt`. – Charles Duffy Dec 04 '17 at 22:01
  • OK thanks for pointing me the right way. – AndyM Dec 05 '17 at 15:22

1 Answers1

1

getopt shouldn't be used, but the bash-aware GNU version works fine inside a function, as demonstrated below:

#!/usr/bin/env bash

main() {
    local getopt_results
    getopt_results=$(getopt -s bash -o e:h --long ENVIRONMENT:,HELP:: "$@")

    eval "set -- $getopt_results" # this is less misleading than the original form

    echo "Positional arguments remaining:"
    if (( $# )); then
      printf ' - %q\n' "$@"
    else
      echo "   (none)"
    fi
}

main "$@"

...when saved as getopt-test and run as:

./getopt-test -e foo=bar "first argument" "second argument"

...properly emits:

Positional arguments remaining:
 - -e
 - foo=bar
 - --
 - hello
 - cruel
 - world
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441