fishshell の argprase で未定義の引数を無視
fishshell で任意のコマンドのラッパーコマンドを作成するとき、普段は便利な argparse
の挙動に困ることがあります。
この記事では、そんなときに頼りになる argparse
のオプション -i
を紹介します。
便利な argparse
argparse は、私が fishshell を使い始めた 2 つの理由のうち 1 つになります。
- argparse による便利で簡単なフラグ機能
- completion が豊富にも関わらず、fishshell の起動が迅速
argparse がどのくらい簡単にフラグ処理をかけるのか、少し確認しましょう。 以下の function を含む hoge.fish を編集します。
|
|
この hoge.fish を読み込み function hoge
をフラグ付きで実行してみます。
> source hoge.fish
> hoge -n World --greeting Hello
Hello, World
フラグはショートフラグ、ロングフラグのどちらも定義済みなので、 ショート/ロングのフラグを逆にしても
> hoge --name World -g Hello
Hello, World
ショートフラグのみにしても
> hoge -n World -g Hello
Hello, World
ロングフラグのみにしても問題ありません。
> hoge --name World --greeting Hello
Hello, World
個人的には
fish_trace
を有効にしてデバッグする事が多いので、この作業を阻害しかねないフラグ定義を作成する関数fish_opt
は使いません。 このことは別の記事で書きたいと思います。
argparse
不便な一面
便利な argparse
ですが、不便なときもあります。
私は、検証目的で様々な環境の vCenter を操作し、その際 govc という便利なコマンドを利用します。
接続先の vCenter を簡単に切り替えるために、fishshell でラッパー関数を作ることができれば、日々の作業が捗りそうです。
最初に作ってみた関数はこちら。
|
|
> call_govc --domain test.dev vm.ip /datacenter/vm/VM-1
192.168.11.101
無事にうまく動きます。vm.ip
は後続で指定した仮想マシンに振られている IP アドレスを取得するオプションで、/datacenter/vm/VM-1
は仮想マシンのインベントリパスになります。argparse
では --domain test.dev
のみがパースされ、残りの値は $argv
に残るであろうという目論見が達成できました。
しかし、以下のコマンドを実行するとエラーが発生します。
find
で vCenter のインベントリを検索、-type m
で仮想マシンに対象を絞り、/datacenter
配下のインベントリを検索します。
|
|
2 行目のエラーは argparse
のエラーで、2 行目以降のエラーは call_govc
内で呼び出している govc
が正しい引数を渡されていないために起きるエラーになります。
argparse
のエラーは govc のサブコマンドである find
の引数 -type
を、解析しようとして定義がなかったため起きています。
vm.ip
がうまく実行できたのは、たまたま -
を含むオプションがなかったためです。
この問題は、未定義のフラグについて argparse
が無視して処理をしない、という動きをしてくれれば解決できます。
これを解決してくれるのが、次に説明する -i
オプションとなります。
-i
オプション
argparse
に -i,--ignore-unknown
オプションをつければ期待した処理がなされます。
call_govc
の argparse
に -i
オプションをつけます。
|
|
3 行目の argparse
では、--domain
フラグのみがパースされ、残りの find -type m /datacenter
は $argv
に残ります。
この $argv
が govc に渡されることで、govc のサブコマンドの引数に -
(ハイフン) が含まれていても正常に govc が実行できるようになります。
|
|
-i
オプションの制限
現状では known なショートフラグと unknown なショートフラグをまとめて与えてしまったときに、$argv
のリストから known なショートフラグを外してくれません。
これは公式の argparse のページに記載があります。
> set -l argv -ho
> argparse -i h -- $argv
> echo $argv
-ho
この例では、ショートフラグ h
と o
を $argv
に与えて、argparse では h
のみをショートフラグとして処理しています。
このとき、期待としては echo $argv
で、unknown なショートフラグである o
のみとなって -o
と出力されてほしいところですが、
known なショートフラグ h
を含む -ho
が $argv
に残ってしまいます。
また、最初の unknown なフラグまでしかパースしないともありますが、こちらは確認できませんでした。
Additionally, it can only parse known options up to the first unknown option in the group - the unknown option could take options, so it isn’t clear what any character after an unknown option means.
> set -l argv -l hoge -o fuga -a poyo
> argparse -i l= a= -- $argv
> echo $_flag_a
poyo
> echo $argv
-o fuga
unknown なフラグの後にある -a poyo
をパースして $_flag_a
に poyo
を代入しているし、$argv
からは unknown なフラグの後にある -a poyo
も取り除かれています。unknown なフラグ以降もパースできているようにみえます。
argparse.cpp を細かく追うまでの気力と力量がなく、調査はここまでとなります。ドキュメントを尊重し、known なフラグを前に配置するように心がけたいと思います。