Как вызвать getopts в Bash несколько раз - PullRequest
2 голосов
/ 03 февраля 2010

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

common.sh:

function get_options {
    echo -e "in getoptions"
    echo $OPTIND
    while getopts ":ab:" optionName; do
       [ ... processing code ... ]
    done
}

a.sh

. ./common.sh

function get_local_options {
    echo -e "in getoptions"
    echo $OPTIND
    while getopts ":xy:" optionName; do
       [ ... processing code ... ]
    done
}

get_local_options $*
OPTIND=1
get_options $*

Проблема в том, что если я вызываю a.sh с помощью:

a.sh -x -y foo -a -b bar

get_options останавливает обработку на «foo», так как останавливается на первом «неопции»

Как-нибудь обойтись без переписывания вещей сам?

Ответы [ 5 ]

6 голосов
/ 16 апреля 2010
foo() {
  unset OPTIND
  while getopts ...
  do
  done
}
1 голос
/ 03 февраля 2010

Мне удалось заставить это работать, не уверен, что это то, что вы хотите:

$ cat common.sh
function get_options {
    while getopts ":ab:" optionName
    do
        echo "get_options: OPTARG: $OPTARG, optionName: $optionName"
    done
}
$ cat a.sh
#!/bin/bash

. ./common.sh

function get_local_options {
    while getopts ":xy:" optionName; do
        case $optionName in
            x|y) 
                echo "get_local_options: OPTARG: $OPTARG, optionName: $optionName"
                last=$OPTIND;;
            *) echo "get_local_options, done with $optionName"
                break;;
        esac;
    done
}

last=1
get_local_options $*
shift $(($last - 1))
OPTIND=1
get_options $*
$ ./a.sh -x -y foo -a -b bar
get_local_options: OPTARG: , optionName: x
get_local_options: OPTARG: foo, optionName: y
get_local_options, done with ?
get_options: OPTARG: , optionName: a
get_options: OPTARG: bar, optionName: b
$ ./a.sh -a -b bar
get_local_options, done with ?
get_options: OPTARG: , optionName: a
get_options: OPTARG: bar, optionName: b
0 голосов
/ 28 марта 2017

Здесь есть несколько хороших ответов, но я думаю, что есть простое решение: вам нужно увеличить OPTIND вместо того, чтобы сбросить его до 1. То есть

a.sh

. ./common.sh

function get_local_options {
    echo -e "in getoptions"
    echo $OPTIND
    while getopts ":xy:" optionName; do
       [ ... processing code ... ]
    done
}

get_local_options $*
(( OPTIND++ ))
get_options $*

Таким образом, вы пропустите слово foo в списке аргументов.

0 голосов
/ 12 сентября 2016

Просто попросите ваш общий скрипт предоставить список общих опций и функций для их обработки, а затем попросите другие скрипты добавить в список опций любые опции, которые они могут обработать:

common.sh

OPTS="ab:hv"

common_usage() {
  echo "Common options:"
  echo "  -a     ..."
  echo "  -b arg ..."
  echo "  -h     Show usage"
  echo "  -v     Be verbose"
}

handle_common_opts() {
  case "$1" in
    a) handle_opt_a ;;
    b) handle_opt_b "$2" ;;
    h) usage; exit 0 ;;
    v) be_verbose ;;
  esac
}

a.sh

. common.sh

OPTS="${OPTS}xy:"

usage() {
  echo "Usage: $PROG [options] [arguments...]"
  echo
  common_usage
  echo
  echo "Specific options:"
  echo "  -x     ..."
  echo "  -y arg ..."
}

while getopts "$OPTS" OPT; do
  handle_common_opts "$OPT" "$OPTARG"
  case "$OPT" in
    x) handle_opt_x ;;
    y) handle_opt_y "$OPTARG" ;;
    \?) usage; exit 1 ;;
  esac
done
shift $((OPTIND-1))

handle_remaining_args "$@"

Это имеет следующие преимущества: нет необходимости разыгрывать трюки с внутренним хранением getopts, пользователь может задавать общие и конкретные параметры в любом порядке, обрабатывает нераспознанные параметры в одном месте, а также выполняет функции использования проще в обслуживании.

0 голосов
/ 15 февраля 2010

Я думаю, вам понадобится, чтобы ваш первый процессор getopts создал список элементов командной строки, которые он не обрабатывал.Кроме того, ему придется игнорировать возвращаемое значение вызова getopts: getopts может возвращать ненулевое значение, потому что он попадает в аргумент переключателя командной строки, который он не знает, как обрабатывать.Таким образом, первый процессор getopts должен идти до конца командной строки.Вы не можете доверять своим собственным суждениям о том, когда варианты остановились и начались аргументы.(Ну, как только вы получите два аргумента подряд, вы можете пропустить остальные, но я оставлю это как упражнение.)

Примерно так:

#!/bin/bash

UNHANDLED=()

function getxy {
  while ((OPTIND<=$#)); do
    if getopts ":xy:" opt; then
      case $opt in
        x|y) echo "getxy opt=$<$opt> OPTARG=<$OPTARG>";;
        *) UNHANDLED+=(-$OPTARG);;
      esac
    else
        UNHANDLED+=(${!OPTIND})
        let OPTIND++
    fi
  done
}

function getab {
  while getopts ":ab:" opt; do
  case $opt in
    a|b) echo "getab opt=$<$opt> OPTARG=<$OPTARG>";;
    *) echo "getab * opt=<$opt> OPTARG=<$OPTARG>";;
  esac
  done
}

echo "--- getxy ---"
OPTIND=1
getxy "$@"
# now we reset OPTIND and parse again using the UNHANDLED array
echo "--- getab ---"
OPTIND=1
set -- "${UNHANDLED[@]}"
getab "$@"
# now we get remaining args
shift $((OPTIND-1))
for arg; do
    echo "arg=<$arg>"
done
...