sysモジュールのargv属性を使って、スクリプトファイルに与えられたコマンドライン引数を受け取り、それを処理する方法を紹介する。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
* 本稿は2021年12月21日に公開された記事をPython 3.12.4で動作確認したものです(確認日:2024年7月10日)。
import sys
# sys.argv属性にはpythonコマンドで実行するスクリプトに
# 与えられたコマンドライン引数が渡される(スクリプトファイル名を含む)
print('sys.argv:', sys.argv)
script_file_name = sys.argv[0]
print('script file name:', script_file_name)
cmdline_option0 = sys.argv[1]
print('command line option[0]:', cmdline_option0)
# sys.orig_argv属性にはpythonコマンドに与えられたコマンドライン引数が
# スクリプトファイル名などを含み、全て渡される(Python 3.10以降)
print('sys.orig_argv:', sys.orig_argv)
import sys
for idx, arg in enumerate(sys.argv):
print(f'arg[{idx}]: {arg}')
import sys
def calc(x, y, op='plus'):
if op == 'plus':
return x + y
elif op == 'minus':
return x - y
elif op == 'multi':
return x * y
elif op == 'div':
return x // y
else:
raise ValueError('op must be plus, minus multi or div')
if len(sys.argv) == 3: # 2引数ならそれらを加算
x = float(sys.argv[1])
y = float(sys.argv[2])
result = calc(x, y)
elif len(sys.argv) == 4: # 3引数は「演算子, 値1, 値2」と見なす
op = sys.argv[1]
x = float(sys.argv[2])
y = float(sys.argv[3])
if op in ['plus', 'minus', 'multi', 'div']:
result = calc(x, y, op)
else:
result = 'not supported operation'
else:
result = 'not supported operation'
print(result)
import sys
# コマンドライン引数をオプションの形(-X 値/-X)で指定する例
# 以下の辞書で値がTrueのオプションは、続けてその値を指定するもの
# 値がFalseのオプションは何らかのスイッチ(True/False値を持つ)
# 例:python3 kw_args.py -x hoge -y huga -z
options = {'-x': True, '-y': True, '-z': False}
args = {'x': 'foo', 'y': 'bar', 'z': False} # デフォルト値
for key in options.keys():
if key in sys.argv:
idx = sys.argv.index(key)
if options[key]:
value = sys.argv[idx+1]
if value.startswith('-'):
raise ValueError(f'option {key} must have a value.')
args[key[1:]] = value
del sys.argv[idx:idx+2]
else:
args[key[1:]] = True
del sys.argv[idx]
print("args['x']:", args['x'])
print("args['y']:", args['y'])
print("args['z']:", args['z'])
# 残ったsys.argvの要素は位置引数と考える(スクリプトファイル名を除く)
print(f'positional argument:', sys.argv[1:])
Pythonのスクリプトを実行する際には、その実行に必要な情報を与えたり、振る舞いを変更したりするためにコマンドライン引数として何らかの値を渡せる。例えば、以下のような渡し方が考えられる。
$ python3 foo.py 1 2 ← foo.pyに1と2を渡す
$ python3 foo.py -x 1 -y 1 ← bar.pyの-xオプションと-yオプションに1を指定
最初の例は、Pythonの関数でいうところの位置引数に相当すると考えられる。つまり、コマンドライン引数の順番でその値が意味するところが決まっている。2つ目の例はキーワード引数に相当すると考えられる。つまり、「-オプション名 その値」という形でオプション(キーワード引数名)とその値を指定するものだ。加えて、あるオプションを指定すると、その値がTrue(またはFalse)に、指定しなければその値がFalse(またはTrue)となるようなスイッチと呼ばれる形式の指定も考えられる。
いずれにせよ、このようにしてスクリプトファイルに渡されたコマンドライン引数は、そのスクリプトファイル内で処理する必要がある。Pythonでコマンドライン引数を処理する際には、sysモジュールのargv属性を使うか、argparseモジュールを使用することが多い。本稿では、このうちsys.argv属性を使う方法を紹介する。
sys.argv属性には、スクリプト開始時にコマンドライン引数として渡された値が文字列リストの形で保存される。このとき、先頭にはスクリプトファイル名が、その後にコマンドライン引数が格納される。
import sys
# sys.argv属性にはpythonコマンドで実行するスクリプトに
# 与えられたコマンドライン引数が渡される(スクリプトファイル名を含む)
print('sys.argv:', sys.argv)
script_file_name = sys.argv[0]
print('script file name:', script_file_name)
cmdline_option0 = sys.argv[1]
print('command line option[0]:', cmdline_option0)
上のスクリプトファイル(foo.pyファイル)を以下のようなコマンドライン引数を指定して実行した例を以下に示す。
> python3 foo.py hogehoge hugahuga
sys.argv: ['foo.py', 'hogehoge', 'hugahuga']
script file name: foo.py
command line option[0]: hogehoge
sys.argv属性の先頭要素がスクリプトファイルの名前(foo.py)に、その次の要素がコマンドライン引数になっていることを確認してほしい。
このようにsys.argv属性の要素に対してインデックスを使ってアクセスしようとするときには、そのインデックス位置に要素がなければ、例外が発生することには注意しよう。例えば、コマンドライン引数なしでfoo.pyファイルを実行すると次のように例外が発生する。これはsys.argv[1]が存在しないからだ。
> python3 foo.py
sys.argv: ['foo.py']
script file name: foo.py
Traceback (most recent call last):
File "C:\pytips\pytips_69\test\foo.py", line 11, in <module>
cmdline_option0 = sys.argv[1]
IndexError: list index out of range
インデックスを使って、コマンドライン引数にアクセスするのは、特定の位置にあるコマンドライン引数が特定の意味を持つことを前提としてスクリプトを書く場合となるだろう(例は後述)。
一方、sys.argv属性は単なる文字列リストなので、以下のようにして反復して処理してもよい。
import sys
for idx, arg in enumerate(sys.argv):
print(f'arg[{idx}]: {arg}')
このとき、スクリプトファイルの名前が不要であれば、sys.argv[1:]と書くことで渡されたコマンドライン引数だけを取り出すことも可能だ。コマンドライン引数に与えた値が位置に応じて特定の意味を持つのではなく、反復的に処理できる場合にはこのようにループすればよい。
なお、Python 3.10からはsys.orig_argv属性が追加されている。こちらはPythonの処理系に渡される全てのコマンドライン引数が格納される。
import sys
print('sys.orig_argv:', sys.orig_argv)
以下にこのファイル(bar.pyファイル)を実行する例を示す。
> python3 -i bar.py foo bar baz
sys.orig_argv: ['C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python310\\python.exe',
'-i', 'bar.py', 'foo', 'bar', 'baz']
>>> # python3コマンドに与えた-iオプションにより対話環境が起動した
特定の位置にあるコマンドライン引数が特定の意味を持つことを前提としたスクリプトの例として、2つの値を渡すとそれらを加算した結果を、3つの値を渡すと最初のコマンドライン引数に応じて他の2つの値を加減乗除した結果を返すスクリプトを以下に示す。
import sys
def calc(x, y, op='plus'):
if op == 'plus':
return x + y
elif op == 'minus':
return x - y
elif op == 'multi':
return x * y
elif op == 'div':
return x // y
else:
raise ValueError('op must be plus, minus multi or div')
if len(sys.argv) == 3: # 2引数ならそれらを加算
x = float(sys.argv[1])
y = float(sys.argv[2])
result = calc(x, y)
elif len(sys.argv) == 4: # 3引数は「演算子, 値1, 値2」と見なす
op = sys.argv[1]
x = float(sys.argv[2])
y = float(sys.argv[3])
if op in ['plus', 'minus', 'multi', 'div']:
result = calc(x, y, op)
else:
result = 'not supported operation'
else:
result = 'not supported operation'
print(result)
ここではコマンドライン引数の数を調べて、その値が3ならコマンドラインには2つの値が指定されたものとして加算を行い、4なら演算方法と2つの値が指定されたものとして加減乗除を行うようにしている。なお、既に述べたように、sys.argv属性は文字列を要素とするリストなので、数値型へ事前に変換する必要がある。
実行例を以下に示す。
> python3 calc_pos.py 100 1
101.0
> python3 calc_pos.py minus 100 1
99.0
最初の例は、2引数なので両者を加算した結果が返されている。次の例は、3引数でminusが指定されているので100から1を減算した結果が返されている。
上のサンプルは、スクリプトファイルに渡すコマンドライン引数を位置引数として扱うものだった。コマンドライン引数をオプション(キーワード引数)として扱うコードの簡略的な例を以下に示す。
import sys
options = {'-x': True, '-y': True, '-z': False}
args = {'x': 'foo', 'y': 'bar', 'z': False} # デフォルト値
for key in options.keys():
if key in sys.argv:
idx = sys.argv.index(key)
if options[key]:
value = sys.argv[idx+1]
if value.startswith('-'):
raise ValueError(f'option {key} must have a value.')
args[key[1:]] = value
del sys.argv[idx:idx+2]
else:
args[key[1:]] = True
del sys.argv[idx]
print("args['x']:", args['x'])
print("args['y']:", args['y'])
print("args['z']:", args['z'])
print(f'positional argument:', sys.argv[1:])
この例では、辞書optionsにこのスクリプトファイルがサポートするオプションの種類と、オプションに続いて値の指定が必要かどうかをTrue/Falseで記述している。辞書argsはオプションが指定されなかった場合のデフォルト値を格納している。
forループでは、辞書optionsのキー(「-オプション名」)が、sys.argv属性に受け取ったコマンドライン引数に含まれているかどうかを調べて、そうであれば、オプションの種類(値が必要なオプション/値が不要なスイッチ)に応じて辞書argsの対応するキーの値を設定するようにしている。処理済みのオプションについてはsys.argv属性から削除すれば、最後に残ったものは位置引数的に扱えるかもしれない(サポートしないオプションを渡されていない場合)。
このようにしてコマンドライン引数を処理して、その値を辞書などに保存しておけば、その後のコードでは保存された値に応じて、スクリプトの振る舞いを変更できるようになる。
このコードの実行例を以下に示す。
> python3 kw_args.py -x hogehoge -y hugahuga -z
args['x']: hogehoge
args['y']: hugahuga
args['z']: True
positional argument: []
> python3 kw_args.py -x hogehoge 100 200
args['x']: hogehoge
args['y']: bar
args['z']: False
positional argument: ['100', '200']
最初の例は、-x/-y/-zの全てのオプションを指定している。その結果、辞書argsの値がデフォルト値から書き換えられている。一方、余計なコマンドライン引数は指定しなかったので位置引数に相当するコマンドライン引数はない。次の例では、-xオプションと追加で100と200を与えている。そのため、辞書argsでは-xオプションに対応する値だけが書き換えられ、100と200は位置引数として扱われている。
しかし、コマンドライン引数の処理が複雑になりそうなら、argparseモジュールを使う方がよいだろう。これについては次回解説する。
Copyright© Digital Advantage Corp. All Rights Reserved.