2015-12-30 3 views
4

Я следующий простой код:Как игнорировать недопустимые аргументы с помощью getopts и продолжать синтаксический анализ?

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

и она работает в простых ситуациях, таких как:

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

Однако это не работает следующим образом:

$ ./test.sh foo -f 

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

Как исправить выше пример кода для поддержки недопустимых аргументов?

+0

Что значит «поддерживать недопустимые аргументы»? 'getopts' останавливает синтаксический анализ при первом необязательном (например,' foo' или 'abc'). Что вы пытаетесь заставить его сделать? Не делать этого и разбирать все? –

+0

Чтобы поддерживать недопустимые аргументы в терминах распознавания того, что '-f' был, несмотря на указание неизвестных аргументов, поэтому' -a abc -f' все равно распознает '-f', но похоже, что' getopts' останавливает обработку некорректным аргументом найден. – kenorb

+0

Он останавливается при первом аргументе без опционов (т. Е. 'Abc'). '-a -a -a -a -f' будет печатать неизвестные четыре раза, например. –

ответ

3

Кажется getopts просто выходит из цикла, как только обнаружен какой-то неизвестный аргумент без опциона (abc).

Я нашел следующий обходной путь оборачивать getopts петли в другую петлю:

#!/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 

Пропустите недопустимые аргументы и разорвать петлю, когда максимум аргументов достигаются.

Выход:

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

'-a' не проблема. Значение ** без опции **. Вытащите 'foo' и' abc' из примеров и они работают (как в ваших оригинальных примерах). Вот как функционируют функции 'getopts'. –

+0

Вы действительно * заботитесь * о значении 'abc' в этих примерах? Поскольку этот двойной цикл будет означать, что вы должны вручную переходить к аргументам * снова * и вручную находить его (путем эмуляции логики 'getopts' самостоятельно), если вы это сделаете. –

+0

@EtanReisner Меня не интересуют неизвестные аргументы, такие как 'abc' в то время, так как я могу прочитать его снова в другом месте скрипта. – kenorb

0

Следующая очень неуниверсальна обходной путь со своими собственными проблемами, но это работает, по крайней мере в моем собственном случае использования. Я подозреваю, что вопрос OP представляет собой минимальный пример, призванный продемонстрировать проблему, поэтому он вряд ли применим к «реальной» проблеме.

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

более универсальным было бы увеличение параметров в цикле while, а затем проверка того, являются ли параметры равными числу подстрок в $ @ формы «- [aA-zZ]», –

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" "[email protected]" 
#  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; 
} 
Смежные вопросы