この記事は, Pythonを利用して研究を行なっていく中で私がつまずいてしまったポイントをまとめていくものです。同じような状況で苦しんでいる方々の参考になれば嬉しいです。Pythonつまずきポイント集の目次は以下のページをご覧ください。
環境
●Ubuntu 16.04
●Python 3.7.3
●conda 4.7.12
●pytorch 1.2.0
やりたいこと
bashスクリプトでPythonファイルを実行したい。そのときに引数を渡したい。
背景
みなさんもよくあることだと思うのですが,Pythonファイルの引数を徐々に変えながら実行結果の挙動を見てみたい場面があると思います。例えば,以下のような「test.py」を考えましょう。
import sys
args = sys.argv
print("1つ目の引数は" + args[1])
print("2つ目の引数は" + args[2])
print("-----")
例えば,test.pyの実行結果は以下のようになります。
(Input)
$ test.py 2 5
(Output)
$ 1つ目の引数は2
$ 2つ目の引数は5
$ -----
このtest.pyに与える引数をいくつも考えて,シェルスクリプトに実行させてしまおうというのが本記事の趣旨になります。さて,1つ目の引数としては「1,3,5」,2つ目の引数としては「2,4,6」を考えることにしましょう。
シェルスクリプトを使わなければ,引数の組み合わせ9通り全てに対して
(Input)
$ test.py 1 2
$ test.py 1 4
$ test.py 1 6
$ test.py 3 2
$ test.py 3 4
$ test.py 3 6
$ test.py 5 2
$ test.py 5 4
$ test.py 5 6
と入力する必要がありました。しかし,シェルスクリプトを使えば万事解決します。以下のようなシェルスクリプト「test.sh」を作成してみましょう。
args1=(1 3 5)
args2=(2 4 6)
for a1 in ${args1[@]};do
for a2 in ${args2[@]};do
python test.py ${a1} ${a2}
done
done
このスクリプトの説明をします。まず,冒頭2行で与える引数の配列を準備しています。Pythonとは異なり,カンマ「,」で区切らず,半角スペースで要素を区切っている点に注意が必要です。
次に,要素の配列の長さ分だけ,forループを回しています。bashでは,forループは
for x in y;
do
(行いたい処理)
done
という構文を利用します。この構文は,
for x in y;do
(行いたい処理)
done
のようにdoをfor文の行に持ってくることも可能です。次に,bashで「$」というのは変数ですよというマークを示します。冒頭で作成した配列を指定するために,ドルマーク「$」をつけています。これをつけないと,「args1」という文字列だと認識されてしまうため,注意が必要です。
次に,「[@]」です。これは,配列の長さ(要素数)を取得するための記号だと思って下さい。つまり,以下の行でfor文を宣言していることになります。
# この行でargs1の中に格納されている変数をa1として取り出しながらforループを実行していきます。
for a1 in ${args1[@]};do
test.shでは,このforループを二重にしています。そして,取り出した変数をPythonファイルの引数として渡しています。
# この部分でPythonファイルに引数を渡しています。
python test.py ${a1} ${a2}
さて,test.shの実行結果を見てみましょう。
(Input)
$ bash test.sh
(Output)
$ 1つ目の引数は1
$ 2つ目の引数は2
$ -----
$ 1つ目の引数は1
$ 2つ目の引数は4
$ -----
$ 1つ目の引数は1
$ 2つ目の引数は6
$ -----
$ 1つ目の引数は3
$ 2つ目の引数は2
$ -----
$ 1つ目の引数は3
$ 2つ目の引数は4
$ -----
$ 1つ目の引数は3
$ 2つ目の引数は6
$ -----
$ 1つ目の引数は5
$ 2つ目の引数は2
$ -----
$ 1つ目の引数は5
$ 2つ目の引数は4
$ -----
$ 1つ目の引数は5
$ 2つ目の引数は6
$ -----
見事,手動でPythonファイルを実行させなくてもbashスクリプトが勝手に実行してくれるようになりました!