長いオプションのみでbashコマンドラインでgetoptを使用する方法は?


13

あるgetoptbashのコマンドラインでコマンドが。getopt短いオプション(などgetopt -o axby "$@")で使用でき、短いオプションと長いオプション(などgetopt -o axby -l long-key -- "$@")の両方で使用できますが、長いオプションだけが必要です(つまり、短いオプションはまったく存在しません)が、コマンドgetopt -l long-key -- "$@"はありません--long-keyオプションを正しく解析します。では、長いオプションだけでgetoptコマンドを使用するにはどうすればよいですか?それとも不可能ですか、それともコマンドのバグですか?getopt


internal getoptsにタグ付けしますが、/usr/bin/getoptコマンドを使用しています。
アントン14年

@Anthon申し訳ありませんが、間違ったタグを使用しましたが、300の評価が必要な別のタグを追加するのに十分な評価がありません。ただし、間違ったタグを今削除しました。
ビクター14年

回答:


15

getopt短いオプションがなくても問題ありません。ただし、短い選択肢はないことを伝える必要があります。それは構文の奇抜です—マニュアルから:

何場合-o--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'

OPはあなたの答えを混ぜgetoptsgetopt感染させましたか?コメントから始めてgetopts、言及するだけgetoptです。
アントン14年

@Anthonすべての私の答えはgetopt、GNU coreutilsからのプログラムに関するものであり、それが問題です。というテキストを修正しましたgetopts。ありがとう。getopts長いオプションすらしないので、これはどれにも当てはまりませんgetopts
ジル「SO-悪であるのをやめる」14年

OPには元々getoptsタグがありました。私はあなたの答えを変えたくありませんでした、なぜならあなたは通常あなたが書いていることについて私よりずっとよく知っているからです:
アントン14年

私はこれを理解しようとしてほぼ1時間を失いました。あなたは私にいくつかの無駄なコーヒーを一口節約しました。おかげで...今、このコーヒーをより有効に活用しましょう。☕️– dmmd
1

1

Dunnoについてですgetoptが、getoptsビルトインは次のような長いオプションのみを処理するために使用できます。

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

もちろん、そのままで、長いオプションに引数がある場合は機能しません。しかし、それはできますが、私がこれに取り組むことを学んだように。最初にここに追加しましたが、長いオプションではあまり有用ではないことに気付きました。この場合case (match)、予測可能な1文字だけでフィールドを短縮していました。今、私が知っていることは、短いオプションに優れていることです-未知の長さの文字列をループし、そのオプション文字列に従って単一バイトを選択するときに最も便利です。しかし、オプション引数である場合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

それが私が扱うことになる引数文字列です。今:

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

これは、--デリミタで区切られた1つまたは2つの引数セットを渡すかどうかに応じて、2つの異なる方法のいずれかで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 3acase()関数定義のコマンド置換は、呼び出しシェルが関数の入力ヒアドキュメントを作成するときに評価されますが、呼び出しシェルで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'

argリストを処理する際、caseブロックと一致するかどうかをチェックします。そこで一致するものが見つかった場合、フラグ-がスローされf=optnameます。有効なオプションが再び見つかるまで、現在のフラグに基づいて構築する配列に後続の各引数を追加します。同じオプションが複数回指定された場合、結果は複合され、オーバーライドされません。大文字と小文字を区別しないもの、または無視されるオプションに続く引数は、無視される配列に割り当てられます。

出力は、シェルによってシェル入力に対して自動的にシェルセーフになります。

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

...完全に安全でなければなりません。何らかの理由安全でない場合は、おそらくシェルメンテナーにバグレポートを提出する必要があります。

一致ごとに2種類のエイリアス値を割り当てます。まず、フラグを設定します。これは、オプションが一致しない引数の前にあるかどうかに関係なく発生します。その--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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.