Как бороться с окончанием опций - в гетопц

9

Я использую getopts для разбора аргументов в скриптах bash как

while getopts ":hd:" opt; do
  case $opt in
    d ) echo "directory = $OPTARG"; mydir="$OPTARG"; shift $((OPTIND-1)); OPTIND=1 ;;
    h ) helptext
      graceful_exit ;;
    * ) usage
      clean_up
      exit 1
  esac
done

exeparams="$*"

exeparamsбудет содержать любые непарсированные параметры / аргументы. Поскольку я хочу использовать exeparams для хранения параметров для команды, выполняемой в сценарии (которая может перекрываться с собственными параметрами сценария), я хочу использовать - для завершения параметров, передаваемых сценарию. Если я прохожу, например,

myscript -d myscriptparam -- -d internalparam

exeparams будет держать

-- -d internalparam

Теперь я хочу удалить ведущий, --чтобы передать эти аргументы внутренней команде. Есть ли элегантный способ сделать это, или я могу получить строку, которая содержит только остаток --от getopts?

highsciguy
источник
Помещение shift; OPTIND=1в getoptsцикл, вероятно, не лучший способ сделать это. Это работает только в вашем случае, потому что у вас есть только 2 варианта, а во всех остальных вы просто выходите из скрипта. В противном случае вам понадобится shift; OPTIND=1каждая опция, что означает дублирование кода (плохая практика). Просто сделайте shift $((OPTIND - 1))сразу после окончания цикла - это самый обычный способ и, вероятно, самый эффективный.
jw013

Ответы:

7

Как насчет:

# ... getopts processing ...

[[ $1 = "--" ]] && shift
exeparams=("$@")

Обратите внимание, вы должны использовать массив для хранения параметров. Это будет правильно обрабатывать любые аргументы, содержащие пробелы. Разыменовать массив с"${exeparams[@]}"

Гленн Джекман
источник
1
Предполагается, что между окончанием опций и аргументов нет никаких аргументов --, т. Е. Они script foo -- barбудут переданы foo -- barвнешней программе. Мой ответ не делает этого предположения, поскольку это не было явно указано в вопросе.
jw013
За исключением случаев, когда ОП говорит: «Теперь я хочу удалить ведущий
Гленн Джекман
Это было для примера -- -d internalparams. В любом случае мой ответ достаточно общий, чтобы справиться с любым из этих случаев.
jw013
14

Используйте встроенный shift. Сначала сделайте нормальный getoptsдля вашего скрипта. Как только этот цикл завершится,

shift "$((OPTIND - 1))"

вытеснит все уже обработанные опции.

Оттуда вам придется закончить обработку неопционных аргументов, если они есть, до первой части скрипта (до --). Как только вы столкнетесь с --, сдвиньте его, пока не останется только последняя часть ( -d internalparamчасть, которая идет после --). Один из способов сделать это (используя bashсинтаксис):

while [[ $# -gt 0 ]]; do
    # process next argument
    case $1 in
    foo) # process foo
    ;;
    --) shift; break;; # found '--', discard it and exit loop
    *) # handle unrecognized argument
    ;;
    esac
    # not '--', so discard the argument and continue
    shift
done

Наконец, остается только второй набор опций / аргументов, который вы можете передать. Как НЕ использовать , $*чтобы передать остальные параметры в другую команду. Используйте "$@"вместо этого, что сохраняет оригинальное разбиение слова.

external_command "$@"
jw013
источник
Да, спасибо! Но как именно я нахожу --?
Highsciguy