テキスト比較
#!/usr/bin/env bash
#
# compare_csv.sh
# 使い方:
# ./compare_csv.sh file1.csv file2.csv
# compare_csv.ini から dir1, dir2 を読み込み、
# 引数のファイル名と組み合わせて比較を行います。
set -euo pipefail
# ── ini 読み込み ──
script_name=$(basename "$0")
ini_file="${script_name%.*}.ini"
[ -f "$ini_file" ] || { echo "Error: '$ini_file' not found." >&2; exit 1; }
dir1=$(grep -E '^[[:space:]]*dir1[[:space:]]*=' "$ini_file" | sed 's/^[^=]*=[[:space:]]*//')
dir2=$(grep -E '^[[:space:]]*dir2[[:space:]]*=' "$ini_file" | sed 's/^[^=]*=[[:space:]]*//')
[ -n "$dir1" ] && [ -n "$dir2" ] || { echo "Error: ini に dir1, dir2 を設定してください。" >&2; exit 1; }
# ── 引数チェック ──
[ $# -eq 2 ] || { echo "Usage: $0 file1.csv file2.csv" >&2; exit 1; }
fname1="$1"; fname2="$2"
file1="${dir1%/}/$fname1"; file2="${dir2%/}/$fname2"
# ── ファイル存在・拡張子チェック ──
for f in "$file1" "$file2"; do
[ -f "$f" ] || { echo "Error: '$f' が存在しません。" >&2; exit 1; }
[[ "${f##*.}" == "csv" ]] || { echo "Error: '$f' は .csv ではありません。" >&2; exit 1; }
done
# ── ログ用ベース名作成 ──
name1=$(basename "$file1" .csv)
logbase=$(echo "$name1" | sed 's/[0-9]\+$//')
[ -z "$logbase" ] && logbase="$name1"
timestamp=$(date +"%Y%m%d_%H%M%S")
# ── ソート&差分検出 ──
sorted1=$(mktemp); sorted2=$(mktemp)
trap 'rm -f "$sorted1" "$sorted2"' EXIT
sort "$file1" > "$sorted1"
sort "$file2" > "$sorted2"
count1=$(wc -l < "$sorted1"); count2=$(wc -l < "$sorted2")
diff_cnt=$(( count1 > count2 ? count1 - count2 : count2 - count1 ))
diff1_count=$(comm -23 "$sorted1" "$sorted2" | wc -l)
diff2_count=$(comm -13 "$sorted1" "$sorted2" | wc -l)
# ── 差分フラグ(日本語) ──
if [ "$diff1_count" -gt 0 ] || [ "$diff2_count" -gt 0 ]; then
has_diff="差分あり"
else
has_diff="差分なし"
fi
# ── compare.log 追記 ──
echo "${logbase},${timestamp},${has_diff},${diff_cnt},${diff1_count},${diff2_count}" \
>> compare.log
# ── 個別ログファイル作成 ──
logfile="${logbase}_${timestamp}.log"
if [ "$has_diff" = "差分あり" ]; then
# file1 側の差分を先頭に書き込み
printf "=== Only in %s (count: %d) ===\n" "$file1" "$diff1_count" > "$logfile"
comm -23 "$sorted1" "$sorted2" | head -n 100 >> "$logfile" || true
# file2 側の差分を続けて書き込み
{
printf "\n=== Only in %s (count: %d) ===\n" "$file2" "$diff2_count"
comm -13 "$sorted1" "$sorted2" | head -n 100
} >> "$logfile" || true
message="比較完了: compare.log にサマリ追記、個別ログ: $logfile"
else
# 差分なしでも空ファイルを作成
: > "$logfile"
message="比較完了: compare.log にサマリ追記(差分なし)、個別ログ(空ファイル): $logfile"
fi
# ── 完了メッセージ ──
echo "$message"
ダミーCSV生成
#!/usr/bin/env python3
"""
generate_sample_csv.py
行数と列数を引数で指定してCSVファイルを生成します。
使い方:
python3 generate_sample_csv.py ROWS COLS [-o OUTPUT]
例:
# 10000行×100列を sample.csv に出力
python3 generate_sample_csv.py 10000 100
# 5000行×50列を data.csv に出力
python3 generate_sample_csv.py 5000 50 -o data.csv
"""
import csv
import random
import string
import argparse
def random_string(length=8):
"""ランダムな英数字文字列を返す"""
chars = string.ascii_letters + string.digits
return ''.join(random.choices(chars, k=length))
def main(output_file: str, rows: int, cols: int):
"""CSV のヘッダーとダミーデータを書き出す"""
with open(output_file, 'w', newline='') as f:
writer = csv.writer(f)
# ヘッダー行
#header = [f"col{i+1}" for i in range(cols)]
#writer.writerow(header)
# データ行
for _ in range(rows):
row = [random_string() for _ in range(cols)]
writer.writerow(row)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='行数と列数を指定してダミーCSVを生成'
)
parser.add_argument(
'rows',
type=int,
help='生成する行数 (例: 10000)'
)
parser.add_argument(
'cols',
type=int,
help='生成する列数 (例: 100)'
)
parser.add_argument(
'-o', '--output',
default='sample.csv',
help='出力ファイル名 (デフォルト: sample.csv)'
)
args = parser.parse_args()
# メイン処理
main(args.output, args.rows, args.cols)