Pythonでのオプションパースのおはなし
私は仕事でよくPythonで小さなツールを作成します。ログ解析やログ収集、 日報の加工や共有サーバの自分のアカウントのバックアップ等々。 その際、ツールにコマンドオプションを渡すことはよくあるシチュエーションです。 今日はPythonでのオプションパースのお話を少し。
例として、-tオプションで時刻表示、-vでバージョン表示、 その他文字列指定でファイル内容を表示する(catコマンドみたいな感じ)、 コマンドを作成してみます。
初心者またはものぐさな人向け(sys.argv)
コマンド引数にアクセスできるsys.argvを直接解析すれば 簡易のオプションパーサを作れます。(これをオプションパーサとは言わない気がするが)
#!/usr/bin/env python
__version__ = '0.0.1'
import sys
import time
def usage():
print "usage: magic [OPTION]"
print "[OPTION]"
print " -h : just now"
print " -t : time print"
print " -v : version print"
print ""
if __name__ == '__main__':
if len(sys.argv) == 1:
sys.exit()
if sys.argv[1] == '-h':
usage()
elif sys.argv[1] == '-v':
print "this tool's version is %s" % __version__
elif sys.argv[1] == '-t':
print time.ctime()
else:
print open(sys.argv[1]).read()
煩雑すぎて、逆に初心者にはお奨めできないかも。 sys.argvを直接解析していくのは、一撃必中ツール (オプションが少ない時やツールを作った人しか使わない時)に 限られると思います。 より現実的な方法としては、getoptモジュールやoptparseモジュール を使う方法があります。
古参プログラマ向け(getopt)
getoptモジュール は、UnixのgetoptコマンドまたはC標準関数のgetopt()に 似たインターフェースを提供します。
例を示します。
#!/usr/bin/env python
__version__ = '0.0.1'
import getopt
import sys
import time
def usage():
print "usage: magic [OPTION]"
print "[OPTION]"
print " -h : just now"
print " -t : time print"
print " -v : version print"
print ""
sys.exit()
if __name__ == '__main__':
try:
shortopt = "hvt"
longopt = ["help", "version", "time"]
opts, args = getopt.getopt(sys.argv[1:], shortopt, longopt)
except getopt.GetoptError:
usage()
for o, a in opts:
if o in ('-v', '--version'):
print "this tool's version is %s" % __version__
elif o in ('-h', '--help'):
usage()
elif o in ('-t', '--time'):
print time.ctime()
for f in args:
print open(f).read()
getoptを使うのは開発環境のPythonのバージョンが古い等で optparseモジュールが使えない場面くらいでしょうか。 optparseが使えるのであればgetoptモジュールを使う必要性はあまりないと思います。
ニュータイプ向け(optparse)
より高機能なオプションパーサとして、 optparseモジュール が用意されています。 バージョン2.3から使えます。
例を示します。
#!/usr/bin/env python
__version__ = '0.0.1'
from optparse import OptionParser
import time
if __name__ == '__main__':
p = OptionParser(version="ver:%s" % __version__)
p.add_option('-t', '--time', action='store_true',
help="time print just now.")
opts, args = p.parse_args()
if opts.time:
print time.ctime()
for f in args:
print "file: ", f
print open(f).read()
これからのPythonistaはoptparseモジュールを使うべきです。 ヘルプ表示生成の容易さやパーサ拡張も行えます。
一歩先へ(optcompleteを使う)
optparseモジュールを便利に使うことができるエクステンションモジュールとして optcompleteモジュール があります。
optcompleteモジュールはoptparseモジュールで作成したパーサをもとに、 bashコンプリーションを便利に使うことができます。
まずはインストール。
$ wget http://furius.ca/downloads/optcomplete/releases/optcomplete-1.2.tar.bz2
$ tar xjf optcomplete-1.2.tar.bz2
$ cd optcomplete-1.2
$ python setup.py install
$ cp -p etc/optcomplete.bash /etc/bash_complete.d/optcomplete
では、先ほどのoptparseの例をもとにoptcompleteを使ってみます。
#!/usr/bin/env python
__version__ = '0.0.2'
from optparse import OptionParser
import time
import optcomplete
#optcomplete.debugfn = '/tmp/optcomplete.log'
if __name__ == '__main__':
p = OptionParser(version="ver:%s" % __version__)
p.add_option('-t', '--time', action='store_true',
help="time print just now.")
optcomplete.autocomplete(p)
opts, args = p.parse_args()
if opts.time:
print time.ctime()
for f in args:
print "file: ", f
print open(f).read()
使い方としては、parse_args()をコールする前に、 optcomplete.autocomplete(parser-object)をコールします。 使い方としてはこれだけです。 optcomplete.debugfn で動作ログの出力先を指定できます。
実際に使ってみると以下のようにファイル名の補完とともに コマンドオプションも補完してくれるようになります。 completeコマンドはログインの度に打つ必要があるので、 $HOME/.bashrcファイルあたりに追記しておくとよいと思います。
$ cp optcomp-sample.py /usr/local/bin/optcamp-sample
$ chmod 755 /usr/local/bin/optcamp-sample
$ complete -F _optcomplete optcomp-sample
$ optcomp-sample
--help -h optcomp-sample.py
--time -t optparse-sample.py
--version getopt-sample.py sysargv.py
$