Я неопытен в сценариях оболочки bash и столкнулся с проблемой с bash optarg

Вот небольшой скрипт для воспроизведения проблемы:

#!/bin/sh

while getopts ":a:b:"  opt; do
  case ${opt} in
    a ) echo "a=$OPTARG"
     ;;
    b ) echo "b=$OPTARG"
      ;;
    \? ) echo "Invalid option: $OPTARG" 1>&2 
      ;;
    : ) echo "Invalid option: $OPTARG requires an argument" 1>&2
  esac
done

Когда я пытаюсь это:

./args.sh -a av -b bv

Я получаю ожидаемый результат:

a=av
b=bv

Но когда я опускаю аргумент для -a:

/args.sh -a -b bv

Я получаю этот неудачный результат:

a=-b

Когда я ожидал, что ошибка покажет, что значение -a отсутствует.

Кажется, он принял аргумент -b в качестве значения для -a. Я сделал что-то не так и как мне добиться ожидаемого поведения?

0
NickJ 17 Апр 2020 в 14:02

2 ответа

Лучший ответ

Единственный положительный совет - как вы относитесь к Но когда я опускаю аргумент для '-a' , вы не можете просто перейти к следующей последующей опции. По соглашению getopts a: означает, что вы ожидаете предоставить значение arg для определенного флага.

Так что даже для пропущенного случая вам нужно определить пустую строку, что означает, что значение для arg не определено, т.е.

-a '' -b bv

Или, если вы не ожидаете, что -a получит какие-либо значения arg, лучше измените строку параметров, чтобы они не получали как :ab:.

Любые другие способы обойти это путем проверки, если OPTARG для -a не содержит -, или другие хаки не рекомендуется, так как это не соответствует рабочему процессу getopts() ,

3
Inian 17 Апр 2020 в 11:37

getopts не поддерживает такое обнаружение. Так что нет способа сделать это с getopts.

Вы можете вместо этого написать цикл вокруг аргументов. что-то вроде:

#!/bin/sh

check_option()
{
    case $1 in
        -*)
            return 1
        ;;
    esac

    return 0
}

for opt in $@; do
  case ${opt} in
    -a) shift
        if check_option $1; then
            echo "arg for -a: $1"
            shift
        else
            echo "Invalid option -a"
        fi
     ;;
    -b) shift
        if check_option $1; then
            echo "arg for -b: $1"
            shift
        else
            echo "Invalid option -b"
        fi
     ;;
  esac
done
1
usr 17 Апр 2020 в 11:30