Pythonスクリプト内でbashコマンドのdiffを使用して特定のディレクトリのファイルの差分を取得し、表示する方法を説明します。
diffコマンドの実行と結果の取得
まず、subprocess
モジュールを使用してbashのdiffコマンドを実行し、結果を取得します。
import subprocess
import os
def get_diff(dir1, dir2, filename):
path1 = os.path.join(dir1, filename)
path2 = os.path.join(dir2, filename)
try:
result = subprocess.run(['diff', '-u', path1, path2],
capture_output=True, text=True, check=True)
return result.stdout
except subprocess.CalledProcessError as e:
if e.returncode == 1: # diff found differences
return e.output
else: # other error occurred
raise RuntimeError(f"Error comparing files: {e}")
この関数は、2つのディレクトリ内の同名ファイルのdiffを取得します。
ディレクトリ内のファイル比較
次に、指定されたディレクトリ内のすべてのファイルを比較する関数を作成します。
def compare_directories(dir1, dir2):
diffs = {}
files = os.listdir(dir1)
for filename in files:
if os.path.isfile(os.path.join(dir1, filename)):
diff = get_diff(dir1, dir2, filename)
if diff:
diffs[filename] = diff
return diffs
この関数は、dir1
内のすべてのファイルをdir2
内の対応するファイルと比較し、差分があるファイルのdiffを辞書に格納します。
結果の表示とエラー処理
最後に、結果を表示し、想定外の差分がある場合にエラーを発生させる関数を作成します。
def display_diffs_and_check(dir1, dir2, expected_diffs=[]):
diffs = compare_directories(dir1, dir2)
if not diffs:
print("No differences found.")
return
for filename, diff in diffs.items():
print(f"Differences in {filename}:")
print(diff)
unexpected_diffs = set(diffs.keys()) - set(expected_diffs)
if unexpected_diffs:
raise Exception(f"Unexpected differences found in files: {', '.join(unexpected_diffs)}")
この関数は、ディレクトリ間の差分を表示し、expected_diffs
リストに含まれていない差分がある場合に例外を発生させます。
使用例
以下は、これらの関数を使用する例です:
if __name__ == "__main__":
dir1 = "/path/to/directory1"
dir2 = "/path/to/directory2"
expected_diffs = ["config.ini", "readme.txt"]
try:
display_diffs_and_check(dir1, dir2, expected_diffs)
print("All differences are as expected.")
except Exception as e:
print(f"Error: {e}")
このスクリプトは、2つのディレクトリを比較し、bashのdiffコマンドを使用して差分を表示します。expected_diffs
リストに含まれていないファイルに差分がある場合、エラーメッセージを表示します。
このアプローチにより、Pythonスクリプト内でbashのdiffコマンドを使用して特定のディレクトリのファイルの差分を取得し、画面に表示し、想定外の差分がある場合にエラーを発生させることができます。
ホワイトリストとの照合もしたい場合
import subprocess
import os
# ディレクトリの定義
# dir1: 変更前のログファイルが格納されているディレクトリ
# dir2: 変更後のログファイルが格納されているディレクトリ
dir1 = "/path/to/before_logs"
dir2 = "/path/to/after_logs"
def get_diff(file1, file2):
"""
2つのファイルの差分を取得する関数
Args:
file1 (str): 比較元のファイルパス
file2 (str): 比較先のファイルパス
Returns:
str: diffコマンドの出力結果
Raises:
RuntimeError: diffコマンドが失敗した場合
"""
try:
# diffコマンドを実行し、結果を取得
result = subprocess.run(['diff', file1, file2],
capture_output=True, text=True, check=True)
return result.stdout
except subprocess.CalledProcessError as e:
if e.returncode == 1: # diffコマンドが差分を見つけた場合
return e.output
else: # その他のエラーが発生した場合
raise RuntimeError(f"Error comparing files: {e}")
def check_whitelist(diff, whitelist):
"""
差分がホワイトリストに含まれているかチェックする関数
Args:
diff (str): diffコマンドの出力結果
whitelist (list): 許可される差分のリスト
Returns:
bool: すべての差分がホワイトリストに含まれている場合はTrue、そうでない場合はFalse
"""
for line in diff.split('\n'):
# '<' は削除された行、'>' は追加された行を示す
if line.startswith('<') or line.startswith('>'):
# 差分行がホワイトリストのいずれにも含まれていない場合はFalseを返す
if not any(white in line for white in whitelist):
return False
return True
def compare_directories(whitelist):
"""
2つのディレクトリ内のファイルを比較し、結果を返す関数
Args:
whitelist (list): 許可される差分のリスト
Returns:
dict: ファイル名をキー、差分内容とステータスを値とする辞書
"""
results = {}
files = os.listdir(dir1)
for filename in files:
before_file = os.path.join(dir1, filename)
after_file = os.path.join(dir2, filename)
if os.path.isfile(before_file) and os.path.isfile(after_file):
diff = get_diff(before_file, after_file)
if diff:
is_ok = check_whitelist(diff, whitelist)
results[filename] = {
'diff': diff,
'status': 'OK' if is_ok else 'NG'
}
return results
def display_results(results):
"""
比較結果を表示する関数
Args:
results (dict): compare_directories関数の返り値
"""
for filename, result in results.items():
print(f"File: {filename}")
print(f"Status: {result['status']}")
print("Diff:")
print(result['diff'])
print("-" * 40) # 区切り線
if __name__ == "__main__":
# ホワイトリストの定義
# 許可される差分の文字列をリストで指定
whitelist = ["許可される差分1", "許可される差分2", "許可される差分3"]
# ディレクトリの比較を実行
results = compare_directories(whitelist)
# 結果の表示
display_results(results)