跳到主要内容

文件系统操作(pathlib)

运维脚本里大量工作围绕路径、目录、文件权限展开:收集日志、清理磁盘、批量改配置。Python 3 推荐用标准库 pathlib,比字符串拼接 os.path.join 更安全、可读。


为什么用 pathlib

场景字符串写法pathlib 写法
拼接路径os.path.join(base, "logs", "app.log")base / "logs" / "app.log"
判断存在os.path.exists(p)p.exists()
读文本open(p).read()p.read_text(encoding="utf-8")

Path 对象跨平台处理 /\,减少路径分隔符写错导致的 bug。


常用操作示例

#!/usr/bin/env python3
"""pathlib 运维常见用法:遍历、过滤、创建目录、读写。"""
from pathlib import Path

# 项目根目录(脚本所在目录的上级)
ROOT = Path(__file__).resolve().parent
LOG_DIR = ROOT / "logs"
LOG_DIR.mkdir(parents=True, exist_ok=True) # 不存在则创建,exist_ok 避免重复报错

# 写入巡检结果
report = LOG_DIR / "inspect.txt"
report.write_text("disk_ok\nmem_ok\n", encoding="utf-8")

# 遍历 *.log,按修改时间排序(最旧在前,便于清理)
log_files = sorted(LOG_DIR.glob("*.log"), key=lambda p: p.stat().st_mtime)
for log in log_files:
size_kb = log.stat().st_size / 1024
print(f"{log.name}: {size_kb:.1f} KB")

# 递归查找大文件(>100MB),用于磁盘告警排查
def find_large_files(root: Path, min_mb: int = 100) -> list[Path]:
threshold = min_mb * 1024 * 1024
return [p for p in root.rglob("*") if p.is_file() and p.stat().st_size > threshold]

# 安全删除:只删指定后缀,且必须在 LOG_DIR 下(防误删)
def safe_remove_old_logs(directory: Path, days_hint: str = "*.log") -> int:
removed = 0
for f in directory.glob(days_hint):
if f.is_file() and f.parent.resolve() == directory.resolve():
f.unlink()
removed += 1
return removed

权限与元数据

from pathlib import Path
import stat

cfg = Path("/etc/nginx/nginx.conf")
if cfg.exists():
mode = stat.filemode(cfg.stat().st_mode) # 如 '-rw-r--r--'
print(f"{cfg}: {mode}, owner uid={cfg.stat().st_uid}")

# 复制配置文件到备份目录(shutil 与 pathlib 配合)
import shutil

backup_dir = Path("/var/backups/nginx")
backup_dir.mkdir(parents=True, exist_ok=True)
if cfg.exists():
shutil.copy2(cfg, backup_dir / f"nginx.conf.bak") # copy2 保留 mtime

与 os 模块的配合

pathlib 不替代一切:os.walk 在大目录遍历时仍常用;os.environ 读环境变量;shutil 做复制/移动/打包。

import os
from pathlib import Path

# 环境变量指定日志根目录,缺省用 /var/log
log_root = Path(os.environ.get("LOG_ROOT", "/var/log"))
if not log_root.is_dir():
raise SystemExit(f"日志目录不存在: {log_root}")

实践建议

  1. 脚本内路径用 Path(__file__).resolve().parent 定位,避免依赖当前工作目录 cwd
  2. 写操作前 mkdir(parents=True, exist_ok=True),读操作前 exists() / is_file()
  3. 删除、覆盖前先打印或 dry-run,生产环境加 --dry-run 开关。
  4. 需要 glob 复杂规则时,rglob("**/*.log") 可递归匹配。
提示

下一章用 subprocess 执行 kubectldockersystemctl 等命令;路径与命令输出常一起出现,可先用 pathlib 准备好配置文件再传给子进程。