bashコマンドラインにgetopt
コマンドがあります。 getopt
は、短いオプション(getopt -o axby "$@"
など)で使用でき、短いオプションと長いオプション(
)、しかし今は 長いオプションのみが必要です(つまり、短いオプションはまったく存在しません)が、コマンドgetopt -l long-key -- "$@"
は--long-key
オプションを正しく解析しません。では、 only の長いオプションでgetopt
コマンドを使用するにはどうすればよいですか?それとも不可能ですか、それともgetopt
コマンドのバグですか?
コメント
回答
getopt
は、短いオプションがなくてもまったく問題ありません。しかし、あなたはあなたが短い選択肢がないことをそれに伝える必要があります。 「構文の癖—マニュアルから:
-o
または--options
オプションは最初の部分にあり、2番目の部分の最初のパラメーターは短いオプション文字列として使用されます。
これがテストで起こっていることです。getopt -l long-key -- --long-key foo
は--long-key
をオプションのリストとして扱います-egklnoy
とfoo
を唯一の引数として使用します。
getopt -o "" -l long-key -- "$@"
eg
$ 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 'でと
getopt
はあなたの答えに感染しますか?getopts
にコメントすることから始めて、。 - @Anthon私の答えはすべて、GNUcoreutilsの
getopt
プログラムに関するものです。これが質問の内容です。Igetopts
というテキストを修正しました。ありがとう。getopts
は'長いオプションも実行しないため、getopts
には適用されません。 。 - OPには元々
getopts
タグがありました。私はあなたの答えを変えたくありませんでした、なぜならあなたは通常あなたが書いていることを私よりずっとよく知っているからです:-) - 私はこれを理解しようとしてほぼ1時間を失いました。あなたは私にいくつかの無駄なコーヒーの一口を救った。ありがとう…このコーヒーをもっと有効に活用しましょう。 ☕️
回答
getopt
については知らないが、getopts
ビルトインは、次のような長いオプションのみを処理するために使用できます。
while getopts :-: o do case "$o$OPTARG" in (-longopt1) process ;; (-longopt2) process ;; esac; done
もちろん、そのままです。 ” long-optionsに引数があるはずの場合は機能しますが、実行することはできますが、私がこれに取り組むことを学んだように。最初にここに含めましたが、長いオプションの場合、あまり有用性がないことに気付きました。この場合、case
(match)
フィールドを単一の予測可能な文字で表示します。これは短いオプションに最適です。長さが不明な文字列をループし、オプション文字列に従って単一のバイトを選択する場合に最も便利です。 。しかし、オプションが引数である場合、for var do case $var in
の組み合わせで実行できることはそれほど多くありません。簡単にするためだと思います。
getopt
についても同じことが言えると思いますが、確実に言うには十分な知識がありません。次のarg配列を前提として、私自身の小さなargパーサーを示します。これは主にalias
と。
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
これは、--
区切り文字で区切られた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
そして。acase()
関数定義のコマンド置換は、呼び出し元のシェルが関数のヒアドキュメントを作成するときに評価されますが、acase()
は呼び出し元のシェルで呼び出されたり定義されたりすることはありません。もちろん、サブシェルで呼び出されるため、コマンドラインで目的のオプションを動的に指定できます。
区切りのない配列は、文字列--
で始まるすべての引数に一致するものをacase()
に入力するだけです。
関数サブシェルで実質的にすべての処理を実行します-各argの値を連想名で割り当てられたエイリアスに繰り返し保存します。完了すると、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
。有効なオプションが再び見つかるまで、現在のフラグに基づいて作成する配列に後続の各引数を追加します。同じオプションが複数回指定された場合、結果は複合され、オーバーライドされません。大文字と小文字が区別されないもの、または無視されたオプションに続く引数は、 ignored 配列に割り当てられます。
出力は、シェルによって自動的にシェル入力用にシェルセーフされます。 :
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 を次のように置き換えます。
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
getopts
のタグですが、/usr/bin/getopt
コマンドを使用しています。