Python: コマンド実行と標準出力の文字列操作
Pythonスクリプトで、外部コマンド(unix/linux/cygwinのコマンド)を実行し、その結果(stdoutに出力された文字列)を解析して情報を取得したいことがある。例えば、
- ある処理を実行したときのログファイルが多量にある
- 各ログファイルには決まったフォーマットで、実行時間の情報が1行書かれている
[例] time: 123.4 - それらの実行時間の情報を一覧にしたCSVファイルを出力する
というケースである。
ここで、全ての処理をPythonで書くことも可能だが、実行時間の情報が書かれた1行を取り出すのに、grepを使ってみる。Pythonスクリプトの処理フローは以下だ。
- カレントディレクトリにあるログファイル(*.log)のリストを作成
- grep time: *.logを実行し、標準出力の内容を変数に取得
- “ログファイル名: 実行時間”という形式でCSVファイルに出力する
Pythonスクリプト cmd_grep.py の内容は以下の通り。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim: fileencoding=euc-jp
import os, sys, re, glob, subprocess
import pandas as pd
fname_out = 'grep.csv'
def get_file_list(target='*.log', dir_name=""):
if dir_name == "":
data_dir = "."
else:
data_dir = dir_name
return sorted(glob.glob(os.path.join(data_dir + '/' + target)))
"""--------------------------------------
main
--------------------------------------"""
logfiles = get_file_list(target='*.log', dir_name='.')
print('found ' + str(len(logfiles)) + ' files')
cmd = ['/bin/grep', 'time:'] + logfiles
result = subprocess.run(cmd, stdout=subprocess.PIPE)
lines = result.stdout.splitlines()
print('found ' + str(len(lines)) + ' results')
log_list = []
elaps_list = []
for l in lines:
s = re.search('([\.\w]+):\s*time:\s+([\d\.]+)', str(l))
if s:
log = s.group(1)
elaps = float(s.group(2))
print("{}: {:6.1f}".format(log, elaps))
log_list.append(log)
elaps_list.append(elaps)
"""--------------------------------------
output CSV
--------------------------------------"""
df = pd.DataFrame()
df['log'] = pd.Series(log_list)
df['time'] = pd.Series(elaps_list)
df.to_csv(fname_out)
sys.exit(0)
ログファイルの例 time1.log~time3.logの中身は以下とする。
$ more time*.log
::::::::::::::
time1.log
::::::::::::::
hogehoge
time: 123.4
::::::::::::::
time2.log
::::::::::::::
foobar
time: 456.7
::::::::::::::
time3.log
::::::::::::::
xyz
time: 89.01
実行時の画面表示は以下のようになる。
$ ./cmd_grep.py
found 3 files
found 3 results
time1.log: 123.4
time2.log: 456.7
time3.log: 89.0
そして、Pythonスクリプトが出力したCSVファイルは以下のようになる。
$ more grep.csv
,log,time
0,time1.log,123.4
1,time2.log,456.7
2,time3.log,89.01
Pythonを覚えて間がないので、もっとスマートな書き方があるかもしれないが、まずはこれで目的を達成できた(そもそも、Pythonでgrepを呼び出さず、テキストファイルの中身をre.search()で走査するので十分だが、あえて外部コマンドを呼んだ)。
ディスカッション
コメント一覧
まだ、コメントがありません