转:https://www.reddit.com/r/ClaudeAI/comments/1r2snly/cleanup_sc...

我每天使用Claude Code大约一个月,注意到我的 ~/.claude 目录占了1.3GB。没有自动清理,会议数据不断堆积。

空间去哪儿了?

du -sh ~/.claude/*/ | sort -rh
目录大小存储内容
projects/1.0 GB会话日志(UUID.jsonl + UUID目录) 会话日志(UUID.jsonl + UUID 目录)
debug/145 MB调试日志
shell-snapshots/83 MBShell环境快照
file-history/23 MB文件编辑历史(撤消)
todos/8.6 MB每会话TODO文件
plans/1.3 MB计划模式输出
其他~800 KB任务、粘贴缓存、图片缓存、安全警告状态_*.json

最大的罪魁祸首是 projects/。每次会话创建一个 UUID.jsonl (完整对话日志)和一个 UUID/ 目录(子代理输出,计划文件)。这些用于 claude --resume <session-id> ,但你很少会重新启动超过一周的会话。

重要:不要碰 memory/

在每个项目目录中,有一个 memory/ 文件夹,包含 MEMORY.md ——这是Claude Code在会话间的持久记忆。删除它你将失去该项目的所有学习上下文。

脚本

我写了一个清理脚本,带有以下安全功能:

  • 默认干运行——除非你传递 --execute,否则不会删除任何内容
  • 双重保护——检查目录名称和UUID模式
  • 可配置年龄——默认为7天,传递任何数字以更改

保存到 ~/.claude/scripts/cleanup-sessions.sh

#!/bin/bash
set -euo pipefail

CLAUDE_DIR="$HOME/.claude"
PROJECTS_DIR="$CLAUDE_DIR/projects"
MAX_AGE_DAYS=7
DRY_RUN=true

numfmt_bytes() {
  local bytes=$1
  if [ "$bytes" -ge 1073741824 ]; then
    printf "%.1f GB" "$(echo "$bytes / 1073741824" | bc -l)"
  elif [ "$bytes" -ge 1048576 ]; then
    printf "%.1f MB" "$(echo "$bytes / 1048576" | bc -l)"
  elif [ "$bytes" -ge 1024 ]; then
    printf "%.1f KB" "$(echo "$bytes / 1024" | bc -l)"
  else
    printf "%d B" "$bytes"
  fi
}

cleanup_files() {
  local dir="$1" pattern="$2" label="$3"
  local count=0 bytes=0
  [ -d "$dir" ] || return 0
  while IFS= read -r -d '' file; do
    local size
    size=$(stat -f%z "$file" 2>/dev/null || echo 0)
    bytes=$((bytes + size))
    count=$((count + 1))
    $DRY_RUN || rm -f "$file"
  done < <(find "$dir" -maxdepth 1 -name "$pattern" -type f -mtime +"$MAX_AGE_DAYS" -print0)
  if [ "$count" -gt 0 ]; then
    echo "  $label: ${count} 个文件 ($(numfmt_bytes "$bytes"))"
    total_files=$((total_files + count))
    total_bytes=$((total_bytes + bytes))
  fi
}

cleanup_dir_contents() {
  local dir="$1" label="$2"
  local count=0 bytes=0
  [ -d "$dir" ] || return 0
  while IFS= read -r -d '' file; do
    local size
    size=$(stat -f%z "$file" 2>/dev/null || echo 0)
    bytes=$((bytes + size))
    count=$((count + 1))
    $DRY_RUN || rm -f "$file"
  done < <(find "$dir" -type f -mtime +"$MAX_AGE_DAYS" -print0)
  if [ "$count" -gt 0 ]; then
    echo "  $label: ${count} 个文件 ($(numfmt_bytes "$bytes"))"
    total_files=$((total_files + count))
    total_bytes=$((total_bytes + bytes))
  fi
}

for arg in "$@"; do
  [[ "$arg" == "--execute" ]] && DRY_RUN=false
  [[ "$arg" =~ ^[0-9]+$ ]] && MAX_AGE_DAYS="$arg"
done

$DRY_RUN && echo "=== 干运行(添加 --execute 以实际删除) ===" \
         || echo "=== 执行模式 ==="
echo "目标:超过${MAX_AGE_DAYS}天的文件"
echo ""

total_files=0
total_dirs=0
total_bytes=0

echo "[项目/会话日志]"
for project_dir in "$PROJECTS_DIR"/*/; do
  [ -d "$project_dir" ] || continue
  project_name=$(basename "$project_dir")
  project_files=0 project_dirs=0 project_bytes=0

  while IFS= read -r -d '' file; do
    size=$(stat -f%z "$file" 2>/dev/null || echo 0)
    project_bytes=$((project_bytes + size))
    project_files=$((project_files + 1))
    $DRY_RUN || rm -f "$file"
  done < <(find "$project_dir" -maxdepth 1 -name "*.jsonl" -type f -mtime +"$MAX_AGE_DAYS" -print0)

  while IFS= read -r -d '' dir; do
    dirname=$(basename "$dir")
    [[ "$dirname" == "memory" ]] && continue
    if [[ "$dirname" =~ ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ ]]; then
      size=$(du -sk "$dir" 2>/dev/null | cut -f1)
      project_bytes=$((project_bytes + size * 1024))
      project_dirs=$((project_dirs + 1))
      $DRY_RUN || rm -rf "$dir"
    fi
  done < <(find "$project_dir" -maxdepth 1 -type d -mtime +"$MAX_AGE_DAYS" -not -path "$project_dir" -print0)

  if [ $((project_files + project_dirs)) -gt 0 ]; then
    echo "  $project_name: ${project_files} 个文件, ${project_dirs} 个目录 ($(numfmt_bytes $project_bytes))"
    total_files=$((total_files + project_files))
    total_dirs=$((total_dirs + project_dirs))
    total_bytes=$((total_bytes + project_bytes))
  fi
done
echo ""

echo "[其他临时数据]"
cleanup_dir_contents "$CLAUDE_DIR/debug" "调试/"
cleanup_dir_contents "$CLAUDE_DIR/shell-snapshots" "shell快照/"
cleanup_dir_contents "$CLAUDE_DIR/file-history" "文件历史/"
cleanup_dir_contents "$CLAUDE_DIR/todos" "待办事项/"
cleanup_dir_contents "$CLAUDE_DIR/plans" "计划/"
cleanup_dir_contents "$CLAUDE_DIR/tasks" "任务/"
cleanup_dir_contents "$CLAUDE_DIR/paste-cache" "粘贴缓存/"
cleanup_dir_contents "$CLAUDE_DIR/image-cache" "图片缓存/"
cleanup_files "$CLAUDE_DIR" "security_warnings_state_*.json" "安全警告状态"

echo ""
echo "--- 摘要 ---"
echo "文件: ${total_files}"
echo "目录: ${total_dirs} (UUID会话)"
echo "节省空间: $(numfmt_bytes $total_bytes)"
$DRY_RUN && [ $((total_files + total_dirs)) -gt 0 ] && echo "" && echo "要删除: $0 ${MAX_AGE_DAYS} --execute"

用法

chmod +x ~/.claude/scripts/cleanup-sessions.sh

# 干运行(默认,不删除任何东西)
~/.claude/scripts/cleanup-sessions.sh

# 将年龄阈值更改为14天
~/.claude/scripts/cleanup-sessions.sh 14

# 实际删除
~/.claude/scripts/cleanup-sessions.sh 7 --execute

我在4周后的结果

文件: 6,806
目录: 246 (UUID会话)
节省空间: 1.3 GB

你绝对不应该清理的文件

路径原因
projects/*/memory/持久记忆(MEMORY.md)
CLAUDE.md全局指令
settings.json用户设置
commands/自定义斜杠命令
plugins/已安装的插件
history.jsonl命令历史

Linux用户注意

这个脚本使用macOS stat -f%z。在Linux上,替换为 stat --format=%s 或使用 wc -c < "$file" 以实现跨平台兼容性。


迹_Jason
1k 声望66 粉丝

feeling主义者,追求极致的简约,创造最好的用户体验