Pythonのglobで条件を満たすパスの一覧を再帰的に取得する方法

 

Pythonのglobモジュールは、ワイルドカードパターンを使用してファイルやディレクトリを検索する強力なツールです。本記事では、再帰的な検索を含むglobの様々な使用方法を詳しく解説します。

globの基本的な使い方

基本的なワイルドカード検索

import glob

# 現在のディレクトリの.txtファイルを取得
txt_files = glob.glob("*.txt")
print(txt_files)  # ['file1.txt', 'file2.txt']

# 特定のパターンにマッチするファイルを取得
python_files = glob.glob("test_*.py")
print(python_files)  # ['test_main.py', 'test_utils.py']

複数文字のワイルドカード

import glob

# 任意の文字列にマッチ
files = glob.glob("data_*.csv")
print(files)  # ['data_2023.csv', 'data_backup.csv']

# 単一文字のワイルドカード
files = glob.glob("file?.txt")
print(files)  # ['file1.txt', 'file2.txt'] (fileA.txtは除外)

再帰的な検索

基本的な再帰検索

import glob

# サブディレクトリを含むすべての.pyファイルを取得
py_files = glob.glob("**/*.py", recursive=True)
print(py_files)
# ['main.py', 'src/utils.py', 'tests/test_main.py']

特定の階層での検索

import glob

# 2階層下までの.txtファイルを取得
txt_files = glob.glob("*/*/*.txt")
print(txt_files)  # ['docs/api/readme.txt']

# 任意の階層の特定ディレクトリ内のファイル
config_files = glob.glob("**/config/*.ini", recursive=True)
print(config_files)

pathlibを使用したモダンなglob

pathlibのglob機能

from pathlib import Path

path = Path(".")

# 基本的な検索
txt_files = list(path.glob("*.txt"))
print([f.name for f in txt_files])

# 再帰的な検索
py_files = list(path.glob("**/*.py"))
print([str(f) for f in py_files])

rglob()を使用した再帰検索

from pathlib import Path

path = Path(".")

# rglob()は自動的に再帰検索を行う
py_files = list(path.rglob("*.py"))
print([str(f) for f in py_files])

# 特定パターンの再帰検索
test_files = list(path.rglob("test_*.py"))
print([f.name for f in test_files])

高度な検索パターン

複数の拡張子を同時に検索

import glob
from pathlib import Path

# globでの方法
extensions = ['*.txt', '*.md', '*.rst']
doc_files = []
for ext in extensions:
    doc_files.extend(glob.glob(f"**/{ext}", recursive=True))

print(doc_files)

# pathlibでの方法
path = Path(".")
doc_files = []
for ext in ['.txt', '.md', '.rst']:
    doc_files.extend(path.rglob(f"*{ext}"))

print([str(f) for f in doc_files])

特定のディレクトリを除外した検索

from pathlib import Path

def find_files_excluding_dirs(root_path, pattern, exclude_dirs):
    root = Path(root_path)
    results = []
    
    for file in root.rglob(pattern):
        # 除外ディレクトリが親パスに含まれていないかチェック
        if not any(excluded in file.parts for excluded in exclude_dirs):
            results.append(file)
    
    return results

# 使用例:__pycache__とnode_modulesを除外
py_files = find_files_excluding_dirs(".", "*.py", ["__pycache__", "node_modules"])
print([str(f) for f in py_files])

実践的な使用例

ログファイルの日付別検索

import glob
from datetime import datetime

# 特定日付のログファイルを検索
date_pattern = "2024-01"
log_files = glob.glob(f"**/logs/*{date_pattern}*.log", recursive=True)
print(log_files)

# 今月のログファイルを検索
current_month = datetime.now().strftime("%Y-%m")
current_logs = glob.glob(f"**/logs/*{current_month}*.log", recursive=True)
print(current_logs)

ファイルサイズによるフィルタリング

from pathlib import Path

def find_large_files(root_path, pattern, min_size_mb):
    root = Path(root_path)
    large_files = []
    
    for file in root.rglob(pattern):
        if file.is_file():
            size_mb = file.stat().st_size / (1024 * 1024)
            if size_mb >= min_size_mb:
                large_files.append({
                    'path': str(file),
                    'size_mb': round(size_mb, 2)
                })
    
    return large_files

# 10MB以上の画像ファイルを検索
large_images = find_large_files(".", "*.{jpg,png,gif}", 10)
for img in large_images:
    print(f"{img['path']}: {img['size_mb']}MB")

最新の更新日時でソート

from pathlib import Path
import glob

def get_recent_files(pattern, count=5):
    files = glob.glob(pattern, recursive=True)
    file_info = []
    
    for file_path in files:
        path = Path(file_path)
        if path.is_file():
            mtime = path.stat().st_mtime
            file_info.append({
                'path': str(path),
                'mtime': mtime
            })
    
    # 更新時間でソート(新しい順)
    file_info.sort(key=lambda x: x['mtime'], reverse=True)
    return file_info[:count]

# 最新の5つの.pyファイルを取得
recent_py_files = get_recent_files("**/*.py")
for file_info in recent_py_files:
    print(file_info['path'])

パフォーマンスを考慮した検索

大量ファイルの効率的な検索

from pathlib import Path
import os

def efficient_search(root_path, extensions, max_depth=None):
    """効率的なファイル検索"""
    root = Path(root_path)
    results = []
    
    def search_directory(directory, current_depth=0):
        if max_depth and current_depth >= max_depth:
            return
            
        try:
            for item in directory.iterdir():
                if item.is_file() and item.suffix.lower() in extensions:
                    results.append(item)
                elif item.is_dir() and not item.name.startswith('.'):
                    search_directory(item, current_depth + 1)
        except PermissionError:
            # 権限のないディレクトリをスキップ
            pass
    
    search_directory(root)
    return results

# 使用例
image_files = efficient_search(".", ['.jpg', '.png', '.gif'], max_depth=3)
print(f"見つかった画像ファイル: {len(image_files)}件")

条件付き検索の組み合わせ

from pathlib import Path
import fnmatch

def complex_search(root_path, include_patterns, exclude_patterns=None):
    """複雑な条件での検索"""
    root = Path(root_path)
    results = []
    exclude_patterns = exclude_patterns or []
    
    for file in root.rglob("*"):
        if not file.is_file():
            continue
            
        # インクルードパターンのチェック
        included = any(fnmatch.fnmatch(file.name, pattern) 
                      for pattern in include_patterns)
        
        # エクスクルードパターンのチェック
        excluded = any(fnmatch.fnmatch(str(file), pattern) 
                      for pattern in exclude_patterns)
        
        if included and not excluded:
            results.append(file)
    
    return results

# 使用例:Pythonファイルを検索、テストファイルとキャッシュを除外
py_files = complex_search(
    ".",
    include_patterns=["*.py"],
    exclude_patterns=["*/test_*", "*/__pycache__/*", "*/.*/*"]
)
print([str(f) for f in py_files])

まとめ

globモジュールとpathlibは、条件を満たすファイルを効率的に検索するための強力なツールです。単純なワイルドカード検索から複雑な条件での再帰検索まで、様々な用途に対応できます。大量のファイルを扱う場合は、パフォーマンスを考慮した実装を心がけ、用途に応じて適切な方法を選択することが重要です。

■プロンプトだけでオリジナルアプリを開発・公開してみた!!

■AI時代の第一歩!「AI駆動開発コース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<月1開催>放送作家による映像ディレクター養成講座

<オンライン無料>ゼロから始めるPython爆速講座