2016-10-17 1 views
1

Я использую getopts для анализа аргументов в сценарии bash. Я хочу сделать две вещи:Может ли getopts разобрать подмножество аргументов сценария bash и оставить остальное неповрежденным?

считают командной строки

$ foo -a val_a -b val_b -c -d -e -f val_f positional_l positional_2 ... 

Где foo использует getopts для разбора параметры, определенные в optstring из 'b:c' и после этого нужно оставить "[email protected]" в

`-a val_a -d -e -f val_f positional_l positional_2 ...` 

мне нужно сделать две вещи:

  • разбора набор опций, которые могут быть предоставлены
  • оставить все другие opptions нетронутыми

Причина этого в том, что foo должен использовать параметры, которые он распознает, для определения другого сценария bar, которому он должен передать оставшиеся "@".

Обычно getopts останавливается, когда встречается с непризнанной опцией, но мне нужно его продолжать (до любого --). Мне нужно это, чтобы обработать и удалить параметры, которые он распознает, и оставить в покое те, которые этого не делают.


Я попытался обойти мою проблему с помощью -- между foo вариантами и bar вариантами, но getopts кажется, сруб, если текст после -- начинается с - (я пытался, но не смог избежать дефиса).

Во всяком случае я предпочел бы не должен использовать -- потому что я хочу существование bar быть эффективно прозрачно для вызывающей foo, и я хотел бы вызывающий из foo, чтобы иметь возможность представить варианты в любом порядке ,

Я также попытался перечислять все bar варианты в foo (т.е. с использованием 'a:b:cdef:' для строка_опций) без их обработки, но мне нужно, чтобы удалить обработанные те из "[email protected]", как они происходят. Я не мог понять, как это сделать (shift не позволяет указать позицию).


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

+1

Одна проблема (казалось бы, непреодолимая): если вы видите '-a -b 3', это неизвестный параметр' -a' без аргумента, за которым следует ожидаемая опция '-b', или это неизвестный параметр' -a' с аргументом '-b', за которым следует позиционный аргумент' 3'? – chepner

+0

@chepner: Хорошая точка. Другая проблема: параметр '-ab'' -a' с параметром-аргументом 'b' или группа опций для интерпретации как' -a' и '-b'? – mklement0

+1

Это выглядит еще более insurmountabler :) – chepner

ответ

2

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

#!/usr/bin/env bash 

passThru=() # init. pass-through array 
while getopts ':cb:' opt; do # look only for *own* options 
    case "$opt" in 
    b) 
     file="$OPTARG";; 
    c) ;; 
    *) # pass-thru option, possibly followed by an argument 
     passThru+=("-$OPTARG") # add to pass-through array 
     # see if the next arg is an option, and, if not, 
     # add it to the pass-through array and skip it 
     if [[ ${@: OPTIND:1} != -* ]]; then 
     passThru+=("${@: OPTIND:1}") 
     ((++OPTIND)) 
     fi 
     ;; 
    esac 
done 
shift $((OPTIND - 1)) 
passThru+=("[email protected]") # append remaining args. (operands), if any 

./"$file" "${passThru[@]}" 

предостережений: Есть два типа неясностей, которые не могут быть решен таким образом :

  • Для опционов pass-thru с опционными аргументами, этот подход работает только в том случае, если аргумент не напрямую прилагается к опции.
    Например, -a val_a работает, но -aval_a бы не (при отсутствии a: в getopts аргумента, это будет истолковано как вариант группы и превратить его в несколько вариантов -a, -v, -a, -l, -_, -a).

  • Как chepner точки в комментарии по этому вопросу, -a -b может быть вариант -a с опцией-аргумент -b (который как раз случается выглядеть как сам вариант), или это может быть различные варианты -a и -b; вышеупомянутый подход сделает последний.

Чтобы устранить эти неясности, вы должны придерживаться with your own approach, который имеет вниз сторона требует знания всех возможных пропускания через параметры заранее.

+1

Подобно тому, что у меня было, кроме случая с шаблоном.Я думаю, что эти предостережения довольно неясны и разумно неосведомлены, чтобы получить выгоду, не требуя предварительного знания аргументов pass-thru. Я не оценил, что вы можете изменить переменные getopts. Хорошее решение. – starfry

2

Вы можете вручную перестроить список опций, как этот пример, который обрабатывает параметры -b и -c и передает все оставленные без изменений.

#!/bin/bash 
while getopts ":a:b:cdef:" opt 
do 
    case "${opt}" in 
    b) file="$OPTARG" ;; 
    c) ;; 
    *) opts+=("-${opt}"); [[ -n "$OPTARG" ]] && opts+=("$OPTARG") ;; 
    esac 
done 
shift "$((OPTIND-1))" 
./$file "${opts[@]}" "[email protected]" 

Так

./foo -a 'foo bar' -b bar -c -d -e -f baz one two 'three and four' five 

будет вызывать bar, учитывая в качестве аргумента опции b как

./bar -a 'foo bar' -d -e -f baz one two 'three and four' five 

Это решение страдает тем недостатком, что строка_опций должна включать и введя пароль (например, ":a:b:cdef:" вместо предпочтительных ":b:c").


Замена списка аргументов с реконструированной один можно сделать так:

set -- "${opts[@]}" "[email protected]" 

, который оставил бы "[email protected]", содержащий необработанные аргументы, как указано в вопросе.

Смежные вопросы