文件系统操作(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}")
实践建议
- 脚本内路径用
Path(__file__).resolve().parent定位,避免依赖当前工作目录cwd。 - 写操作前
mkdir(parents=True, exist_ok=True),读操作前exists()/is_file()。 - 删除、覆盖前先打印或 dry-run,生产环境加
--dry-run开关。 - 需要 glob 复杂规则时,
rglob("**/*.log")可递归匹配。
提示
下一章用 subprocess 执行 kubectl、docker、systemctl 等命令;路径与命令输出常一起出现,可先用 pathlib 准备好配置文件再传给子进程。