긴 옵션만 사용하여 bash 명령줄에서 getopt를 사용하는 방법은 무엇입니까?

긴 옵션만 사용하여 bash 명령줄에서 getopt를 사용하는 방법은 무엇입니까?

getoptbash 명령줄에 명령이 있습니다. getopt이는 짧은 옵션(예: getopt -o axby "$@")에서 작동하고 짧고 긴 옵션(예: getopt -o axby -l long-key -- "$@")에서 작동하지만 이제 다음이 필요합니다.오직긴 옵션(즉, 짧은 옵션이 전혀 존재하지 않음)이지만 명령이 옵션을 올바르게 구문 분석 getopt -l long-key -- "$@"할 수 없습니다 . 그렇다면 명령을 --long-key어떻게 사용할 수 있습니까?getopt오직긴 옵션? 아니면 이것이 불가능합니까, 아니면 명령의 버그입니까 getopt?

답변1

getopt단기적인 옵션이 없어도 괜찮습니다. 하지만 단기적인 옵션이 없다고 말해야 합니다. 이것은 매뉴얼의 특이한 구문입니다.

첫 번째 부분에 no -o또는 option이 없으면 --options두 번째 부분의 첫 번째 인수가 짧은 옵션 문자열로 사용됩니다.

이것이 테스트에서 일어나는 일입니다. 이를 옵션 목록 이자 유일한 매개변수 getopt -l long-key -- --long-key foo라고 생각하세요 . 사용--long-key-egklnoyfoo

getopt -o '' -l long-key -- "$@"

예를 들어

$ getopt -l long-key -o '' -- --long-key foo
 --long-key -- 'foo'
$ getopt -l long-key -o '' -- --long-key --not-recognized -n foo
getopt: unrecognized option '--not-recognized'
getopt: invalid option -- 'n'
 --long-key -- 'foo'

답변2

모르겠지만 내장 함수는 다음과 같이 긴 옵션을 처리하는 데에만 사용할 수 있습니다 getopt.getopts

while getopts :-: o
do  case "$o$OPTARG" in
(-longopt1) process ;;
(-longopt2) process ;;
esac; done

물론, 긴 옵션에 매개변수가 있어야 하는 경우에는 작동하지 않습니다. 하지만 제가 이 분야에서 일하면서 배운 것을 토대로 하면 가능합니다. 원래는 여기에 넣었지만 장기적인 옵션에는 별로 쓸모가 없다는 것을 깨달았습니다. 이 경우에는 case (match)예측 가능한 문자로 내 분야가 단축되었습니다. 이제 나는 이것이 짧은 옵션에 적합하다는 것을 알고 있습니다. 길이를 알 수 없는 문자열을 반복하고 해당 옵션 문자열을 기반으로 단일 바이트를 선택할 때 가장 유용합니다. 하지만 옵션이 있을 때for var do case $var in아, 할 수 있는 조합으로는 할 수 있는 일이 많지 않습니다. 간단하게 유지하는 것이 가장 좋다고 생각합니다.

나는 이것이 사실이라고 생각 getopt하지만 그것에 대해 확실하게 말할 만큼 지식이 없습니다. 다음 arg 배열이 주어지면 나는 나만의 작은 arg 파서를 시연할 것입니다. 이는 주로 alias및 에 대한 평가/할당 관계 에 따라 달라집니다 $((shell=math)).

set -- this is ignored by default --lopt1 -s 'some '\'' 
args' here --ignored   and these are ignored \
--alsoignored andthis --lopt2 'and 

some "`more' --lopt1 and just a few more

이것이 제가 사용할 arg 문자열입니다. 지금:

aopts() { env - sh -s -- "$@"
} <<OPTCASE 3<<\OPTSCRIPT
acase() case "\$a" in $(fmt='
        (%s) f=%s; aset "?$(($f)):";;\n'
        for a do case "$a" in (--) break;;
        (--*[!_[:alnum:]]*) continue;;
        (--*) printf "$fmt" "$a" "${a#--}";;
        esac;done;printf "$fmt" '--*' ignored)
        (*) aset "" "\$a";;esac
shift "$((SHIFT$$))"; f=ignored; exec <&3 
OPTCASE
aset()  {  alias "$f=$(($f${1:-=$(($f))+}1))"
        [ -n "${2+?}" ] && alias "${f}_$(($f))=$2"; }
for a do acase; done; alias
#END
OPTSCRIPT

--arg 배열을 한 세트 또는 구분 기호로 구분된 두 개의 인수 세트로 전달하는지 여부에 따라 두 가지 방법 중 하나로 처리합니다 . 두 경우 모두 arg 배열의 처리 순서에 적용됩니다.

다음과 같이 호출하면:

: $((SHIFT$$=3)); aopts --lopt1 --lopt2 -- "$@"

첫 번째 작업은 acase()다음과 같이 함수를 작성하는 것입니다.

acase() case "$a" in 
    (--lopt1) f=lopt1; aset "?$(($f)):";;
    (--lopt2) f=lopt2; aset "?$(($f)):";;
    (--*) f=ignored; aset "?$(($f)):";;
    (*) aset "" "$a";;esac

그리고 측면에서 shift 3. acase()호출 쉘이 함수의 입력 문서를 작성할 때 함수 정의의 명령 대체가 평가되지만 acase()호출 쉘에서 호출되거나 정의되지는 않습니다. 물론 서브셸에서 호출되므로 명령줄에서 원하는 옵션을 동적으로 지정할 수 있습니다.

acase()분리되지 않은 배열을 제공하면 string 으로 시작하는 모든 인수에 대한 일치 항목을 채웁니다 --.

이 함수는 서브셸에서 거의 모든 처리를 수행합니다. 즉, 각 인수 값을 연관된 이름이 할당된 별칭에 반복적으로 저장합니다. 완료되면 저장된 모든 값을 인쇄합니다. alias이는 해당 값을 셸에 다시 입력할 수 있는 방식으로 해당 값을 참조하여 저장된 모든 값을 인쇄하는 POSIX 사양입니다. 그래서 내가 이 일을 할 때...

aopts --lopt1 --lopt2 -- "$@"

출력은 다음과 같습니다.

...ignored...
lopt1='8'
lopt1_1='-s'
lopt1_2='some '\'' args'
lopt1_3='here'
lopt1_4='and'
lopt1_5='just'
lopt1_6='a'
lopt1_7='few'
lopt1_8='more'
lopt2='1'
lopt2_1='and

some "`more'

인수 목록을 반복하면서 케이스 블록이 일치하는지 확인합니다. 거기에서 일치하는 항목을 찾으면 - 플래그를 던집니다 f=optname. 유효한 옵션을 다시 찾기 전에 현재 플래그를 기반으로 구축하는 배열에 각 후속 인수를 추가합니다. 동일한 옵션을 여러 번 지정하면 결과가 복합되어 덮어쓰여지지 않습니다. 케이스에 속하지 않거나 옵션 뒤의 인수를 무시하는 모든 항목은 다음에 할당됩니다.무시당하다대량으로.

출력은 쉘에 안전하며 쉘 입력은 쉘에 의해 자동으로 이루어집니다. 따라서 다음과 같습니다.

eval "$(: $((SHIFT$$=3));aopts --lopt1 --lopt2 -- "$@")"

...절대적으로 안전해야 합니다. 만약 어떤 이유에서든아니요보안을 위해서는 쉘 관리자에게 버그 보고서를 제출해야 합니다.

각 일치 항목에 두 개의 별칭 값을 할당합니다. 첫째, 플래그를 설정합니다. 이는 옵션이 일치하지 않는 인수 앞에 오는지 여부에 관계없이 발생합니다. 따라서 --flag인수 목록에 있는 모든 항목이 트리거됩니다 flag=1. 그것은 복합적이지 않습니다 . --flag --flag --flag단지 flag=1. 이 값하다하지만 증분 - 뒤에 올 수 있는 모든 인수에 대해. 인덱스 키로 사용할 수 있습니다. 위의 작업을 수행한 후 eval다음을 수행할 수 있습니다.

printf %s\\n "$lopt1" "$lopt2"

...얻기 위해...

8
1

그래서:

for o in lopt1 lopt2
do list= i=0; echo "$o = $(($o))"
        while [ "$((i=$i+1))" -le "$(($o))" ]
        do list="$list $o $i \"\${${o}_$i}\" "
done; eval "printf '%s[%02d] = %s\n' $list";  done

산출

lopt1 = 8
lopt1[01] = -s
lopt1[02] = some ' args
lopt1[03] = here
lopt1[04] = and
lopt1[05] = just
lopt1[06] = a
lopt1[07] = few
lopt1[08] = more
lopt2 = 1
lopt2[01] = and

some "`more

일치하지 않는 매개변수는 교체하겠습니다.무시당하다위의 필드에서 for ... in다음을 얻습니다.

ignored = 10
ignored[01] = this
ignored[02] = is
ignored[03] = ignored
ignored[04] = by
ignored[05] = default
ignored[06] = and
ignored[07] = these
ignored[08] = are
ignored[09] = ignored
ignored[10] = andthis

관련 정보