パソコンの中にいつの間にか増える「中身が同じファイル」を、名前ではなく内容で見つけて整理します。そこでPythonのTyperでコマンドを組み立て、Richで結果を色付きの表に見せる重複ファイル整理ツールを作ってみました。
中核はSHA-256ハッシュによる内容照合で、seed・scan・organizeの3つのサブコマンドを使い「サンプル生成→重複表示→退避」まで一通り動かせます。初心者でも追体験できるよう、コードを断片ごとに噛み砕いて解説していきます。
Typerの基本概念、要件定義、実装、動作確認までを順番に学べる構成です。動画は目次から確認したい場面へ移動でき、本文だけでも手順と考え方が完結します。
動画の内容をテキストで確認する
オープニング。TyperとRichを使って重複ファイル整理CLIを作るカリキュラムを始めます。概要紹介。
TyperとRichの役割と使い方を学ぶ 重複ファイル整理CLIの要件を整理する 完成コードと実行結果を確認する 最後に実コマンドとファイル状態で完成挙動を確かめる 具体的にやること。内容が同じファイルを検出する 重複を色付きの表で一覧する お試し用のサンプルを生成する 余分なコピーを移動先へ整理する 各グループの原本を1つ残す 実装環境・必須アプリ。
OS:Windows 11 Pro Python:3.13.3シェル:PowerShell 5.1必須アプリ:コードエディター、ターミナル、エクスプローラー パッケージ:pip、typer、rich TyperとRichとは。
PythonでCLIを作るライブラリのTyper:関数をそのままコマンドにできる 結果を見やすく表示するライブラリのRich:表を組んで整然と見せる TyperとRichで重複ファイル整理CLIを作る際の重要ポイント。SHA-256で内容を要約する 同じハッシュを同一内容とみなす 大きなファイルはチャンクで読む 重複ファイル整理CLIの要件定義。
seedで6個のサンプルが作られるscanで重複グループが表に並ぶ 重複がなければその旨を知らせるorganizeで原本が残りコピーが移動する 最後に移動件数が表示される 確認1/3: サンプルファイルを作成する。seedコマンドを実行し、重複を含む6個のサンプルファイルが作成される様子を確認します。確認2/3: 重複ファイルを一覧する。
scanコマンドを実行し、同じ内容のファイルと余分なコピーの件数を表で確認します。確認2/3: 重複ファイルを一覧する。scanコマンドを実行し、同じ内容のファイルと余分なコピーの件数を表で確認します。
確認3/3: 余分なコピーを安全に移動する。organizeコマンドを実行し、原本を残して余分なコピーだけが退避される結果を確認します。確認3/3: 余分なコピーを安全に移動する。
organizeコマンドを実行し、原本を残して余分なコピーだけが退避される結果を確認します。学習内容のまとめ。関数をそのままコマンドにできる 表を組んで整然と見せるSHA-256で内容を要約する 名前ではなく内容で判定する 小さく実行確認しながら完成状態まで段階的に組み立てる エンディング。
Python研修はCodeCampでご確認ください。
TyperとRichとは
今回使用する主要なライブラリについて、役割と使い分けを順番に確認します。
CLIを作るライブラリのTyper
Typerは、Pythonの関数をそのままコマンドラインツールに変えられるライブラリです。引数の型ヒントを書くだけで入力の受け取りやヘルプ表示を自動で用意してくれるため、コマンドの骨組みづくりに集中できます。今回のツールでも、seedとscanとorganizeという3つの関数がそのままサブコマンドになっています。
難しい設定を書かずにCLIを組み立てられる点が、初心者にとって大きな魅力といえるでしょう。
- 関数をそのままコマンドにできる
- 型ヒントから引数を自動解釈する
- ヘルプを自動生成する
- 複数のサブコマンドをまとめられる
結果を見やすく表示するライブラリのRich
Richは、ターミナルの出力を色付きの文字や整った表で見せられるライブラリです。標準のprintでは味気ない実行結果も、Consoleオブジェクトを通せば重要な部分を強調できます。このツールでは重複ファイルの一覧をTableで組み立て、グループ番号やハッシュを列ごとに整理して表示しています。
結果が読みやすくなり、どのファイルが重複しているのかを一目で把握できるでしょう。
- 表を組んで整然と見せる
- 色やスタイルを文字に付ける
- Consoleオブジェクトで出力する
Python・Typerで開発する場合の環境構築
この記事のセットアップ手順と掲載コードは、Windows 11 Pro、PowerShell 5.1、Python 3.13.3、Typer 0.27.0で動作確認しています。仮想環境を有効化せず、その中のPythonを直接指定するため、以下のコマンドはPowerShellとコマンドプロンプト(cmd)の両方で使えます。
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install --upgrade pip
.\.venv\Scripts\python.exe -m pip install typer rich
macOS・Linuxでは仮想環境内のPythonパスが異なります。今回の動作確認環境とは異なるため、以下は環境差分を補う参考手順です。
python3 -m venv .venv
./.venv/bin/python -m pip install --upgrade pip
./.venv/bin/python -m pip install typer rich
- typerを入れるとrichも依存として入りますが、Richを明示的に使うので併記して導入しています。
- organizeの--destは走査対象フォルダの外側(例: ./duplicates)を指定すると、整理後のscanで移動済みコピーを拾わずに済みます。
PythonのTyperとRichで作る重複ファイル整理CLIの要件定義
目的は、内容が同じファイルをハッシュで見つけて整理することです。
対象者として、PythonでCLIツールの作り方を学びたい人を想定しています。
完成物は、TyperとRichで作る重複ファイル整理CLIです。
実装へ入る前に、機能・品質・受け入れ条件を分けて確認します。
機能要件
- 内容が同じファイルを検出する
- 重複を色付きの表で一覧する
- お試し用のサンプルを生成する
- 余分なコピーを移動先へ整理する
- 各グループの原本を1つ残す
- 移動先フォルダを指定できる
非機能要件
- 名前ではなく内容で判定する
- 大きなファイルもチャンク読みで扱える
- 3つのサブコマンドで操作を分ける
- 標準ライブラリ中心で構成する
実装方針
今回はTyperとRichの基本動作を追いやすくするため、重複ファイル整理CLI本体を1つのPythonファイルへまとめます。
入力、判定、結果表示の役割を分け、実行結果を確認しながら機能を積み上げます。
- TyperとRichのコマンド定義と処理関数の責務を分ける
- 入力フォルダやオプションを検証してからファイル処理を始める
- 時間のかかる処理は進捗を表示し、結果を確認できるようにする
- 削除ではなく退避を選び、誤判定から戻せる設計にする
完成と判断する条件
- seedで6個のサンプルが作られる
- scanで重複グループが表に並ぶ
- 重複がなければその旨を知らせる
- organizeで原本が残りコピーが移動する
- 最後に移動件数が表示される
TyperとRichで重複ファイル整理CLIを作る際の重要ポイント
このツールの心臓部は、ファイルの内容をSHA-256というハッシュ値に要約して比べる仕組みです。名前や場所が違っても中身が同じならば同じハッシュになるため、コピーを確実に見つけ出せます。大きなファイルでもメモリを圧迫しないよう、内容を少しずつ読み込みながら計算していく点も工夫のひとつでしょう。
整理の場面では各グループの先頭を原本として残し、余分なコピーだけを移動先へ退避させています。
- SHA-256で内容を要約する
- 同じハッシュを同一内容とみなす
- 大きなファイルはチャンクで読む
- 原本を1つ残しコピーを退避する
ハッシュで内容を比べる理由
ファイル名やサイズだけでは、本当に中身が同じかどうかは判断できません。SHA-256はファイルの内容から一意の文字列を生成するので、この値が一致すれば内容も同じだと安心して扱えます。
- 名前では同一と断定できない
- 内容から一意の値を作る
- 値の一致で重複を判定する
重複グループのまとめ方
defaultdictを使い、同じハッシュを持つファイルを一つのリストへ集めていきます。集計後に要素が2つ以上あるものだけを残せば、重複しているグループだけを取り出せます。
- ハッシュをキーに集約する
- 2件以上を重複とみなす
- 単独のファイルは除外する
原本を残して整理する流れ
各グループの先頭を原本として残し、残りのコピーだけを移動先へ動かします。移動先に同名のファイルがある場合は連番を付け、既存のファイルを上書きしないよう配慮しています。
- 先頭を原本として残す
- 余りを移動先へ動かす
- 同名は連番で退避する
PythonのTyperとRichで作る重複ファイル整理CLIの完成コード
動画の内容をテキストで確認する
INTRO: Typerを使ったCLI開発を開始。コードを1行ずつ入力し、節目ごとに実行結果を確かめながら完成させます。LINE 001: hashlibの読み込み。
ファイルの中身からハッシュ値を計算するための標準ライブラリhashlibを読み込みます。後半のcompute_hash関数で、同じ内容かどうかを見分けるために使います。LINE 002: shutilの読み込み。
ファイルのコピーや移動を扱う標準ライブラリshutilを読み込みます。organizeコマンドで余分なコピーを別フォルダへ移すときに利用します。LINE 003: defaultdictの読み込み。
存在しないキーにも自動で初期値を用意してくれるdefaultdictを読み込みます。ハッシュ値ごとにファイルの一覧をまとめる処理を短く書くために使います。LINE 004: Pathの読み込み。
ファイルやフォルダの場所をオブジェクトとして扱えるPathを読み込みます。パスの結合や再帰的な走査を、文字列操作より安全に書けるようになります。LINE 006: Typerの読み込み。
コマンドライン用のツールを手軽に作れるライブラリtyperを読み込みます。このあとseedやscanといったサブコマンドを定義する土台になります。LINE 007: Consoleの読み込み。
Richの装飾付き表示を担うConsoleクラスを読み込みます。色付きのメッセージや表をターミナルにきれいに出力するために使います。LINE 008: Tableの読み込み。
Richで整った罫線付きの表を作るTableクラスを読み込みます。scanやorganizeの結果を見やすい一覧にして見せるのに役立ちます。LINE 010: アプリ本体の作成。
typer.Typerでツール全体の本体を作ります。add_completion=Falseで補完機能を省き、helpにはツールの説明文を設定しています。LINE 011: コンソールの準備。
画面出力に使うConsoleオブジェクトを一つ作り、consoleという名前で共有します。以降はこれを通じて色付きメッセージや表を表示します。RUN 1/7: TyperのappとRichのConsoleを準備する。
importと初期化が終わり、コマンドを束ねるappと出力を担うconsoleが用意できた段階です。まだコマンドはありませんが、オブジェクトが正しく作れているかを確認できます。CHECK 1/7: 途中実行に成功。
app: Typer console: Console LINE 014: ハッシュ計算の節の説明。ここからはファイルの中身をハッシュ値に変換する関数を定義します。大きなファイルでも一度に全部読まず、少しずつ読む工夫をする点を示しています。
LINE 015: compute_hash関数の定義。ファイルのパスを受け取ってハッシュ値の文字列を返すcompute_hash関数を定義します。chunk_sizeは一度に読み込むバイト数で、初期値は65536バイトです。
LINE 016: ハッシュ計算器の用意。SHA-256方式でハッシュを計算するためのオブジェクトをdigestとして作ります。このあとファイルの中身を少しずつ渡して、最終的な値を組み立てます。
LINE 017: ファイルをバイナリで開く。対象のファイルを"rb"モードで開き、変数fとして扱います。バイナリで読むことで、テキストでも画像でも同じ方法で中身を処理できます。
LINE 018: チャンク単位の繰り返し。iterを使い、ファイルからchunk_size分ずつ読み取ってchunkに取り出す繰り返しを作ります。空のバイト列b""が返ったら読み終わりとして自動で止まります。
LINE 019: ハッシュへの取り込み。読み込んだ一区切り分のデータをdigestに渡して、ハッシュの計算を少しずつ進めます。この積み重ねでファイル全体の特徴を一つの値にまとめます。
LINE 020: ハッシュ値の返却。計算し終えたハッシュ値を、扱いやすい16進数の文字列に変換して返します。この文字列が、ファイルの中身を見分けるための指紋の役割を果たします。
RUN 2/7: ファイルのハッシュ計算を実装する。compute_hash関数が完成し、ファイルの内容からSHA-256の値を求められるようになりました。試しに小さなファイルを作り、ハッシュの先頭だけを表示して動きを確かめます。
CHECK 2/7: 途中実行に成功。hash: 2cf24dba5f LINE 023: 重複検出の節の説明。ここからは、内容がまったく同じファイルを一つのグループにまとめる関数を作ります。
ハッシュ値が一致するものを重複とみなす方針を示しています。LINE 024: find_duplicate_groups関数の定義。調べたいフォルダを受け取り、ハッシュ値をキーにファイル一覧を値とする辞書を返す関数を定義します。
この結果が各コマンドの重複判定のもとになります。LINE 025: 集計用辞書の用意。ハッシュ値ごとにファイルをまとめるための辞書hashesを、defaultdict(list)で用意します。
新しいハッシュ値が出てきても、自動で空のリストが割り当てられます。LINE 026: フォルダの再帰走査。rglobで指定フォルダの中身をサブフォルダまで含めてたどり、sortedで順番をそろえて一つずつpathに取り出します。
並べ替えることで結果の順序が毎回安定します。LINE 027: ファイルかどうかの判定。取り出したpathがフォルダではなくファイルであるかをis_fileで確認します。
ファイルのときだけ次のハッシュ計算へ進めます。LINE 028: ハッシュごとの振り分け。compute_hashでそのファイルのハッシュ値を求め、同じ値のリストにパスを追加します。
これで中身が同じファイルが自然と同じグループに集まります。LINE 029: 重複グループの絞り込み。集めた辞書のうち、ファイルが2つ以上ある項目だけを残して返します。
1つしかないものは重複ではないため、ここで除外しています。RUN 3/7: 重複グループを検出する処理を加える。find_duplicate_groupsが加わり、フォルダ内の同一内容ファイルをまとめられるようになりました。
中身が同じ2つのファイルを置き、検出されるグループ数を数えて確かめます。CHECK 3/7: 途中実行に成功。groups: 1 LINE 032: サンプル生成の節の説明。
ここからは、動作を試すための重複入りサンプルを作るコマンドを用意します。手元にファイルがなくてもすぐツールを体験できるようにする目的です。LINE 033: コマンドとしての登録。
@app.commandを付けて、次に定義する関数をツールのサブコマンドとして登録します。これでコマンドラインからseedとして呼び出せるようになります。LINE 034: seedコマンドの定義。
サンプルを作る先のフォルダを引数として受け
コードは、ハッシュ計算とグループ検出という2つの部品を土台に、3つのサブコマンドをかぶせる構成にしています。
compute_hashとfind_duplicate_groupsが中核のロジックで、seed・scan・organizeはそれらを呼び出す薄い入り口という役割分担です。
表示まわりはRichのConsoleとTableに任せ、ファイルの移動は標準ライブラリのshutilに委ねました。以降で押さえるべき要点だけを断片ごとに見ていきます。
このセクションの用語
- defaultdict
- 存在しないキーへアクセスすると自動で初期値(ここでは空リスト)を用意してくれる辞書です。追加処理を短く書けます。
- rglob
-
Pathのメソッドで、サブフォルダも含めて再帰的にファイルを列挙します。 - shutil
- ファイルのコピーや移動をまとめて扱えるPython標準ライブラリです。ここでは
shutil.moveで退避に使います。
import hashlib
import shutil
from collections import defaultdict
from pathlib import Path
import typer
from rich.console import Console
from rich.table import Table
app = typer.Typer(add_completion=False, help="TyperとRichで作る重複ファイル整理ツール")
console = Console()
# ファイルのハッシュ計算(チャンク読みで大きなファイルにも対応)
def compute_hash(path: Path, chunk_size: int = 65536) -> str:
digest = hashlib.sha256()
with path.open("rb") as f:
for chunk in iter(lambda: f.read(chunk_size), b""):
digest.update(chunk)
return digest.hexdigest()
# 重複グループの検出(内容が同一のファイルをまとめる)
def find_duplicate_groups(directory: Path) -> dict[str, list[Path]]:
hashes: dict[str, list[Path]] = defaultdict(list)
for path in sorted(directory.rglob("*")):
if path.is_file():
hashes[compute_hash(path)].append(path)
return {h: paths for h, paths in hashes.items() if len(paths) > 1}
# お試し用サンプルの生成
@app.command()
def seed(directory: Path = typer.Argument(..., help="サンプルを作成するフォルダ")):
"""重複を含むサンプルファイルを作成し、ツールをすぐ試せるようにする。"""
directory.mkdir(parents=True, exist_ok=True)
(directory / "backup").mkdir(exist_ok=True)
samples = {
"report.txt": "四半期の売上レポート\n",
"report_copy.txt": "四半期の売上レポート\n",
"logo.dat": "BINARY-LOGO-DATA",
"backup/logo.dat": "BINARY-LOGO-DATA",
"backup/report_bak.txt": "四半期の売上レポート\n",
"notes.txt": "重複しない個別のメモ\n",
}
for rel, content in samples.items():
(directory / rel).write_text(content, encoding="utf-8")
console.print(f"[green]サンプルを作成しました[/]: {directory} に {len(samples)} 個のファイル")
# 重複ファイルの一覧表示
@app.command()
def scan(directory: Path = typer.Argument(..., help="走査するフォルダ")):
"""フォルダを再帰的に走査し、重複ファイルを表にして表示する。"""
groups = find_duplicate_groups(directory)
if not groups:
console.print(f"[green]重複はありません[/]: {directory}")
raise typer.Exit()
table = Table(title=f"重複ファイル: {directory}")
table.add_column("グループ", justify="right", style="cyan")
table.add_column("ハッシュ", style="magenta")
table.add_column("サイズ", justify="right")
table.add_column("ファイル")
for i, (h, paths) in enumerate(groups.items(), start=1):
size = paths[0].stat().st_size
files = "\n".join(str(p) for p in paths)
table.add_row(str(i), h[:10], f"{size} B", files)
console.print(table)
extra = sum(len(paths) - 1 for paths in groups.values())
console.print(f"[yellow]余分なコピー: {extra} 件[/]")
# 重複ファイルの整理(原本を1つ残し、コピーを移動)
@app.command()
def organize(
directory: Path = typer.Argument(..., help="整理するフォルダ"),
dest: Path = typer.Option("duplicates", "--dest", "-d", help="コピーの移動先フォルダ"),
):
"""各グループで最初の1つを原本として残し、余分なコピーを移動先へ整理する。"""
groups = find_duplicate_groups(directory)
if not groups:
console.print(f"[green]整理する重複はありません[/]: {directory}")
raise typer.Exit()
dest.mkdir(parents=True, exist_ok=True)
moved = 0
table = Table(title="整理結果")
table.add_column("残した原本", style="green")
table.add_column("移動したコピー", style="yellow")
for paths in groups.values():
keep, *copies = paths
for copy in copies:
target = dest / copy.name
counter = 1
while target.exists():
target = dest / f"{copy.stem}_{counter}{copy.suffix}"
counter += 1
shutil.move(str(copy), str(target))
table.add_row(str(keep), str(target))
moved += 1
console.print(table)
console.print(f"[green]{moved} 件のコピーを {dest} へ移動しました[/]")
if __name__ == "__main__":
app()
コード全文は上の折り畳みに入れてあるので、全部を上から読む必要はありません。ここでは特に重要な部分だけを抜き出して、何をしているのか順番に見ていきます。
typer.Typerでアプリの土台を作る
app = typer.Typer(add_completion=False, help="TyperとRichで作る重複ファイル整理ツール")
console = Console()typer.Typer()でコマンドをぶら下げる本体を1つ用意します。ここに@app.command()で各機能を登録していく形です。RichのConsoleも先に作っておき、色付き出力の窓口として使い回します。
compute_hashでチャンク読みしながらSHA-256を求める
digest = hashlib.sha256()
with path.open("rb") as f:
for chunk in iter(lambda: f.read(chunk_size), b""):
digest.update(chunk)
return digest.hexdigest()ファイルをバイナリで開き、chunk_sizeずつ小分けに読みながらハッシュへ流し込みます。巨大なファイルでも一度に全部メモリへ載せないので安全です。最後にhexdigest()で16進の文字列に変換して返します。
find_duplicate_groupsでハッシュ別にまとめる
hashes: dict[str, list[Path]] = defaultdict(list)
for path in sorted(directory.rglob("*")):
if path.is_file():
hashes[compute_hash(path)].append(path)
return {h: paths for h, paths in hashes.items() if len(paths) > 1}rglob("*")でサブフォルダまで走査し、ファイルだけをハッシュ値をキーにした辞書へ振り分けます。defaultdictのおかげで初期化を気にせず追加できるのが便利です。最後に、同じキーが2件以上ある組だけを重複として絞り込んで返します。
RichのTableで列を定義する
table = Table(title=f"重複ファイル: {directory}")
table.add_column("グループ", justify="right", style="cyan")
table.add_column("ハッシュ", style="magenta")
table.add_column("サイズ", justify="right")
table.add_column("ファイル")Tableを作り、add_columnで列の見出し・寄せ方向・色を1つずつ設定します。styleにcyanやmagentaを指定するだけで、ターミナルに色付きの表が描けるのがRichの強みです。
add_rowで重複グループを1行ずつ表に流し込む
for i, (h, paths) in enumerate(groups.items(), start=1):
size = paths[0].stat().st_size
files = "\n".join(str(p) for p in paths)
table.add_row(str(i), h[:10], f"{size} B", files)enumerateで1から始まる通し番号を振りながら、各グループを1行として追加します。h[:10]でハッシュを先頭10文字に短縮し、stat().st_sizeでファイルサイズを取得しました。複数のパスは改行でつないで1つのセルに収めています。
seedコマンドで重複入りサンプルを用意する
samples = {
"report.txt": "四半期の売上レポート\n",
"report_copy.txt": "四半期の売上レポート\n",
"logo.dat": "BINARY-LOGO-DATA",
"backup/logo.dat": "BINARY-LOGO-DATA",
}名前は違っても中身が同じファイルをわざと混ぜたサンプルを書き出します。これで環境を汚さずにscanやorganizeの挙動をすぐ試せます。まずseedで試して感覚をつかむのがおすすめです。
PythonのTyperとRichで作った重複ファイル整理CLIの動作確認
実際にCLIツールを4回のコマンドで実行し、いずれも終了コード0で正常に動作しました。
まずpython subject.py seed ./sample_filesでサンプルを生成し、続けてscanで重複を一覧表示しています。
そのあとpython subject.py organize ./sample_files --dest ./duplicatesで重複コピーを退避し、最後にもう一度scanして重複が解消されたことを確認できました。
scanではRichの色付きテーブルにグループ番号・短縮ハッシュ・サイズ・ファイル一覧が並び、余分なコピー件数もまとめて表示されます。
このセクションの用語
- 終了コード
- コマンドが終わったときに返す番号です。0は正常終了を表し、0以外は何らかのエラーを示します。




PythonのTyperとRich利用時に起きやすいエラーと対処法
初心者が最初につまずきやすいのは、ライブラリの導入漏れと引数の渡し忘れです。
代表的なエラーと、その原因・対処を表にまとめました。メッセージの文言を手がかりに落ち着いて切り分けるのがコツです。
| エラー例 | 原因 | 対処 |
|---|---|---|
| ModuleNotFoundError: No module named 'typer' | TyperやRichが未インストール |
pip install typer richで導入する |
| TypeError: 'type' object is not subscriptable |
dict[str, list[Path]]の記法が古いPythonで動かない |
Python3.9以上を使うかfrom __future__ import annotationsを追加する |
| FileNotFoundError | 存在しないフォルダを引数に渡した | パスの綴りを確認し、先にseedでフォルダを作る |
| PermissionError | 対象や移動先が使用中、または書き込み権限がない | ファイルを閉じ、権限のある場所を--destに指定する |
| Error: Missing argument 'DIRECTORY' | 対象フォルダの引数を渡し忘れた |
python subject.py scan ./sample_filesのように指定する |
重複ファイル整理CLIで注意したい点
organizeは重複と判定したファイルを指定先へ移動します。仕組みを理解しないまま実行すると、残したいファイルまで移動するおそれがあるため、事前に動作の前提を確認しておくことが大切です。
ポイントとしては、重複の判定基準、原本の決まり方、チャンク読みの3点を押さえておきましょう。
判定基準:SHA-256で内容の同一性
原本:各重複グループの先頭を保持
読み込み:チャンク単位で内容を取得
重複ファイル整理ツールが活躍する場面
内容照合という仕組みは、名前がバラバラでも中身が同じファイルを見つけたい場面で効きます。
実務で応用しやすい使い方を、具体的な手順まで踏み込んで挙げてみます。
| 使える場面 | 具体的な使い方 |
|---|---|
| 写真・画像フォルダの整理 | 何度も取り込んで増えた同一画像をscanで洗い出し、organizeで退避してから中身を確認して削除する |
| ダウンロードフォルダの掃除 | 「(1)」付きで二重保存された資料やインストーラを内容照合で見つけ、原本だけ残す |
| バックアップの重複除去 | 複数世代のバックアップ間で中身が同じファイルを検出し、ストレージの無駄を可視化する |
| 納品データの重複チェック | 納品前フォルダをscanし、同一内容のファイルが混在していないか色付きの表で目視確認する |
PythonのTyperとRichによる重複ファイル整理CLI開発のまとめ
TyperとRichを組み合わせると、少ないコードで「使いやすいコマンド」と「見やすい表示」を両立できました。
中核はSHA-256による内容照合というシンプルな発想で、compute_hashとfind_duplicate_groupsさえ理解すれば全体像がつかめます。
まずはseedで作ったサンプルで挙動を確かめ、慣れてきたら自分のフォルダへ少しずつ適用してみてください。
参考にした一次情報
- ^ Typer公式ドキュメント(サブコマンドの作り方). https://typer.tiangolo.com/, (参照26-07-20).
- ^ Rich公式ドキュメント(Tableによる表表示). https://rich.readthedocs.io/en/stable/tables.html, (参照26-07-20).
- ^ Python公式ドキュメントhashlib(SHA-256などのハッシュ計算). https://docs.python.org/ja/3/library/hashlib.html, (参照26-07-20).
- ^ Python公式ドキュメントshutil(ファイルの移動shutil.move). https://docs.python.org/ja/3/library/shutil.html, (参照26-07-20).
※内容は執筆時点のものです。ライブラリやサイトの仕様は変わる可能性があるため、公式ドキュメントもあわせてご確認ください。
ITやプログラミングに関するコラム
【CSS】notで複数の件を除外する方法
【Git】remote設定を変更する方法
【VBA】コメントアウトを設定する方法
x86とx64の違いを分かりやすく解説
マークダウンで改行する方法
CapsLockキーを解除する方法
GitLabとGitHubの違いを解説
Linuxで環境変数を確認する方法
UbuntuのIPアドレスを確認する方法
パソコンのメモリの目安を用途別に選ぶ方法
ITやプログラミングに関するニュース
VercelがAI GatewayにSeedream 5.0 Proを追加、AI SDKのモデル指定で画像生成と編集が可能に
AWSがAmazon LocationのPlaces APIを強化、住所表記の指定と移動手段別の検索が可能に
VercelがトレースにTree・Waterfallビューを追加、ログ画面で処理の階層と所要時間を確認可能に
Googleがエージェント評価の再考を提唱、難易度を情報量で測るDiscovery Benchを解説
Google CloudがCloud Runサンドボックスを公開プレビューで提供、サービスヘルスは一般提供に
Google Cloud EMEAが英国金融の重要第三者に指定、イングランド銀行・PRA・FCAの直接監督下に
AWS DMS Schema ConversionがSQL Serverのオフライン変換に対応、ソースDBへ接続せずスキーマを変換可能に
EC2 G7インスタンスが米国東部(バージニア北部)で利用可能に、G6比でAI推論性能が最大4.6倍
SageMaker HyperPodが継続プロビジョニングでのAMIベース構成に対応、S3のスクリプト管理なしでSlurmクラスターを作成可能に
AWSがEMR on EKSでSparkトラブルシューティングエージェントに対応、失敗ジョブの原因分析を自然言語で依頼可能に
