Захват недопустимых параметров getopt

Я использую getopt (не getops), чтобы предоставить возможность моему скрипту bash обрабатывать параметры и переключатели (как длинные --option, так и короткие-o формы).

Я хотел бы иметь возможность ловить недопустимые параметры и обрабатывать их, как правило, повторяя, что пользователь должен попробовать cmd --help и затем выход из сценария.

дело в том, что недопустимые параметры пойманы getopt, который сам выводит сообщение, такое как " getopt: недопустимый параметр -- 'x'"

вот шаблон, который я использую для установки параметров getopt:

set -- $(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "$@")

где оба $LONG_OPTIONS и $SHORT_OPTIONS являются разделенным запятыми списком опций.

вот как я обрабатываю обработку параметров:

 while [ $# -gt 0 ]
    do
        case "" in
            -h|--help)
                cat <<END_HELP_OUTPUT

    Help
    ----

    Usage: ./cmd.sh 

    END_HELP_OUTPUT

                shift;
                exit
                ;;
            --opt1)
                FLAG1=true
                shift
                ;;
            --opt2)
                FLAG2=true
                shift
                ;;
            --)
                shift
                break
                ;;
            *)
                echo "Option  is not a valid option."
                echo "Try './cmd.sh --help for more information."
                shift
                exit
                ;;
        esac
    done

getopt -q будет подавлять вывод, но моя схема захвата в case заявление по-прежнему не делает то, что я ожидаю. Вместо этого программа просто выполняется, несмотря на недопустимые аргументы.

6 ответов


этой вид стиля работает для меня:

params="$(getopt -o d:h -l diff:,help --name "$cmdname" -- "$@")"

if [ $? -ne 0 ]
then
    usage
fi

eval set -- "$params"
unset params

while true
do
    case  in
        -d|--diff)
            diff_exec=(${2-})
            shift 2
            ;;
        -h|--help)
            usage
            exit
            ;;
        --)
            shift
            break
            ;;
        *)
            usage
            ;;
    esac
done

Это не самое надежное решение, но это разумно; он полагается на следующее:

  • сообщение об ошибке, что getopt печать имеет префикс " getopt:"
  • предполагается, что приемлемо пройти через очищенную версию getoptсообщение об ошибке, дополненное пользовательской информацией.

фрагмент кода:

# Invoke getopt; suppress its stderr initially.
args=$(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "$@" 2>/dev/null)
if [[ $? -ne 0 ]]; then # getopt reported failure
    # Rerun the same getopt command so we can capture stderr output *only* this time.
    # Inefficient (and a potential maintenance headache, if literals were involved), but this will only execute in case of invalid input.
    # Alternatively, redirect the first getopt invocation's stderr output to a temp. file and read it here.
    errmsg=$(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "$@" 2>&1 1>&-)
    # Strip getopt's prefix and augment with custom information.
    echo -e "${errmsg#getopt: }\nTry './cmd.sh --help for more information." 1>&2
    exit 1
fi

вам вообще нужно использовать getopt? Если вы просто используете

while [ $# -gt 0 ]; do
  case "" in
    -d|--diff)
       diff_exec=(${2-})
       shift
       ;;
    -h|--help)
       usage
       exit
       ;;
     --)
       break
       ;;
     *)
       usage
       ;;
    esac
    shift
done

тогда вы собственный код делает проверку.


Я обнаружил, что это работает как последний элемент в заявлении getopts case:

*) eval echo " Unrecognized arg \$$[OPTIND-1]"; Использование; выход ;;


Я не уверен, что это может помочь, но getopt (1) использует getopt (3) и если я правильно помню getopt (3) подавить сообщение об ошибке, если первый символ OPTSTRING двоеточие.


вот синтаксический анализ командной строки, который я использовал. Он может быть улучшен парсинг логика обработки отсутствующих параметров.

для командной строки: - A AA-b BB-CC, результат s/b a=AA b=BB c=CC

OPT=( "$@" )  # Parses the command line into words.

for [[ I=0;I<${#OPT[@]};I++ ]]  
   do
      case "${OPT[$I]}" in         
         -a) a=${OPT[$I+1]} ;;         
         -b) b=${OPT[$I+1]} ;;         
         -c) c=${OPT[$I+1]} ;;    
      esac
  done