How to ignore invalid arguments with getopts and continue parsing?

I have the following simple code:

#!/usr/bin/env bash
while getopts :f arg; do
  case $arg in
    f) echo Option $arg specified. ;;
    *) echo Unknown option: $OPTARG. ;;
  esac
done

and it works in simple scripts such as:

$ ./test.sh -f
Option f specified.
$ ./test.sh -a -f
Unknown option: a.
Option f specified.

However, this does not work for the following:

$ ./test.sh foo -f

$ ./test.sh -a abc -f
Unknown option: a.

How to fix sample code to support invalid arguments?

+4
source share
3 answers

It seems to getoptsjust exit the loop when some unknown optional argument ( abc) is found.

I found the following workaround by wrapping the loop getoptsin another loop:

#!/usr/bin/env bash
while :; do
  while getopts :f arg; do
    case $arg in
      f)
        echo Option $arg specified.
        ;;
      *)
        echo Unknown option: $OPTARG.
        ;;
    esac
  done
  ((OPTIND++)) 
  [ $OPTIND -gt $# ] && break
done

Then skip the invalid arguments and break the loop when the maximum arguments are reached.

Output:

$ ./test.sh abc -f
Option f specified.
$ ./test.sh -a abc -f
Unknown option: a.
Option f specified.
+3

, , , . -, . , , , . .

###############################################################################
#
# Convenience method to test if a command line option is present.
#
# Parameters:
#   $1 - command line argument to match against
#   $2 - command line parameters
#
# Example:
#   is_cmd_line_option_present "v" "$@" 
#       check if the -v option has been provided on the command line
#
###############################################################################
function is_cmd_line_option_present()
{
    _iclop_option="$1"
    # remove $1 from the arguments (via the shift command) to this method before searching for it from the actual command line
    shift
    # Default the return value to zero
    _iclop_return=0

    # Don't need to increment OPTIND each time, as the getopts call does that for us
    for (( OPTIND=1; OPTIND <= $#; ))
    do
        # Use getopts to parse each command line argument, and test for a match
        if getopts ":${_iclop_option}" _iclop_option_var; then
            if [ "${_iclop_option_var}" == "${_iclop_option}" ]; then
                _iclop_return=1
             # else
                # (>&2 echo -e "[Std Err]: is_cmd_line_option_present - Option discarded _iclop_option_var: [${_iclop_option_var}]")
            fi
         else
            # (>&2 echo -e "[Std Err]: is_cmd_line_option_present - Unknown Option Parameter _iclop_option_var: [${_iclop_option_var}]")
            # Need to increment the option indicator when an option is found that isn't listed as an expected option, as getopts won't do this for us.
            ((OPTIND++))
        fi 
    done

    # (>&2 echo -e "[Std Err]: is_cmd_line_option_present end - _iclop_return: [${_iclop_return}]")
    return $_iclop_return;
}
+3

- , , , . , , , "" .

params=0
 while getopts :f arg; do
  params=1
  case $arg in
    f) echo Option $arg specified. ;;
    *) echo Unknown option: $OPTARG. ;;
  esac
done
if [[ ! $@ == '' ]] && ((params == 0 )); then
    echo "wrong arguments"
    exit 1
fi
0

Source: https://habr.com/ru/post/1622268/


All Articles