
1. 项目概述一个被低估的系统清理工具如果你在GitHub上搜索过系统清理工具大概率会看到过elexingyu/cc-cleaner这个项目。乍一看它可能只是众多“CCleaner”开源替代品中的一个名字也带着明显的致敬意味。但作为一个在运维和开发一线摸爬滚打了十多年的老手我必须说这个项目远不止是一个简单的“清理”脚本。它更像是一个针对开发者、运维人员甚至是那些对系统有洁癖的资深用户的“精准外科手术刀”。市面上大多数清理工具无论是老牌的CCleaner还是各种系统自带的“磁盘清理”其逻辑往往是宽泛的、面向大众的。它们会清理浏览器缓存、临时文件、日志这些固然有用但对于我们这些整天与开发环境、多版本SDK、Docker镜像、构建缓存、IDE历史记录打交道的人来说这些工具的清理往往隔靴搔痒甚至可能误伤“友军”。cc-cleaner的核心价值就在于它精准地定位了技术从业者在日常工作中产生的、独特且庞杂的“数字垃圾”并提供了一套可定制、可审计的清理方案。简单来说cc-cleaner是一个用脚本常见如Shell、Python实现的专注于清理软件开发、系统运维过程中产生的缓存、临时文件、日志、残留配置等内容的工具集。它不追求华丽的界面而是强调通过配置文件或命令行参数实现高度可预测和可重复的清理操作。这对于需要频繁重置环境、释放磁盘空间或是在CI/CD流水线中保持构建环境纯净的场景有着不可替代的作用。2. 核心设计思路从“粗放清扫”到“精准排雷”为什么我们还需要一个清理工具系统自带的不够用吗要理解cc-cleaner的设计哲学我们需要先看看技术环境下“垃圾”的特殊性。2.1 技术环境下的“垃圾”分类与普通用户不同我们的系统垃圾更具“专业性”和“隐蔽性”构建缓存与产物node_modules/,target/,dist/,build/,.gradle/,pip缓存、Cargo注册表缓存等。这些目录动辄几个GB且分散在各项目路径下。容器与虚拟化残留退出的Docker容器、悬空的Docker镜像、虚拟机快照、minikube或kind集群的临时文件。IDE与编辑器历史JetBrains全家桶IntelliJ IDEA, PyCharm等的索引、缓存、历史记录VSCode的扩展缓存、用户数据vim/neovim的swap文件、undo历史。包管理器全局缓存apt/yum/dnf的包缓存、brew的缓存与旧版本、npm/yarn/pnpm的全局缓存目录、gem的文档和缓存。日志与诊断文件各种应用日志/var/log/下、系统日志、journalctl日志、特定应用如Docker, kubelet产生的庞杂日志文件。临时下载与解压文件从互联网下载的源码包、工具压缩包解压后常常被遗忘在下载目录或临时目录。一个优秀的、面向技术的清理工具必须能识别并安全地处理以上这些目标同时要避免误删以下关键内容版本控制目录.git/,.svn/等。重要的配置文件如~/.ssh/,~/.aws/, 数据库文件等。正在运行的进程所需文件。2.2cc-cleaner的架构选择基于以上需求cc-cleaner通常采用模块化、配置驱动的架构核心引擎一个主脚本如clean.sh或main.py负责解析配置、调度清理模块、记录日志、处理错误。清理模块每个模块负责一类特定的清理任务。例如docker_cleaner.py,npm_cleaner.sh,ide_cache_cleaner.py。模块化便于维护和扩展。配置文件通常是一个YAML或JSON文件如config.yaml用户在这里定义启用哪些模块、设置排除路径、配置清理策略如“保留最近7天的日志”。安全机制包括模拟运行Dry Run模式只列出将要删除的文件不实际执行、备份机制可选地将文件移动到回收站或备份目录、详细的执行日志。注意任何系统清理操作都具有潜在风险。cc-cleaner的设计必须将“安全”放在首位。在实现中删除操作前应有二次确认或强制性的--force参数并且默认应该开启 Dry Run 模式。2.3 与通用工具的关键差异特性通用清理工具 (如 CCleaner)cc-cleaner(技术向)目标用户普通计算机用户开发者、系统管理员、DevOps工程师清理重点浏览器缓存、系统临时文件、回收站构建缓存、Docker残留、IDE历史、包管理器缓存可定制性低提供图形化复选框极高通过配置文件或代码定义规则可集成性独立桌面应用可作为命令行工具集成到脚本、CI/CD流水线安全性相对安全但可能误删会话恢复数据风险与收益并存需用户明确知晓规则提供Dry Run透明度黑盒操作用户不知具体删了什么白盒操作规则由用户定义日志清晰可查这种设计思路使得cc-cleaner从一个“工具”进化成了一个“解决方案框架”你可以根据自己团队的 tech stack 来定制专属的清理流程。3. 关键模块实现与实操解析一个典型的cc-cleaner实现会包含多个核心模块。下面我们深入几个最常见、也最有效的模块看看它们是如何工作的以及在实际操作中需要注意什么。3.1 模块一构建系统与包管理器缓存清理这是释放空间的大头。我们以npm和Maven为例。npm缓存清理实现思路npm的缓存默认位于~/.npmLinux/macOS或%AppData%\npm-cacheWindows。清理不仅仅是删除~/.npm那么简单因为那里可能还有全局安装的包的链接。更精细的做法是使用npm cache verify命令来验证缓存完整性并清理损坏的数据。使用npm cache clean --force来清理所有缓存数据。遍历项目目录寻找node_modules文件夹。直接删除是最彻底的但有时我们可能想保留当前正在开发项目的node_modules。这就需要通过配置文件指定要清理的项目根路径列表。实操脚本示例 (Shell)#!/bin/bash # 模块: npm_cleaner CONFIG_FILE./config.yaml # 从配置中读取要清理的项目根路径 PROJECT_ROOTS$(yq e .npm_cleaner.project_roots[] $CONFIG_FILE) # 从配置中读取是否清理全局缓存 CLEAN_GLOBAL_CACHE$(yq e .npm_cleaner.clean_global_cache $CONFIG_FILE) echo [INFO] 开始清理 npm 缓存... if [ $CLEAN_GLOBAL_CACHE true ]; then echo - 清理全局 npm 缓存... npm cache verify npm cache clean --force fi for root in $PROJECT_ROOTS; do if [ -d $root ]; then echo - 扫描项目根目录: $root # 使用 find 命令定位 node_modules排除 .git 目录下的 find $root -name node_modules -type d -not -path */.git/* | while read dir; do echo - 删除: $dir # 在实际运行前这里应该有一个判断是否为 dry-run 的逻辑 # if [ $DRY_RUN ! true ]; then # rm -rf $dir # fi done else echo [WARN] 配置的项目路径不存在: $root fi done实操心得直接暴力删除所有node_modules在磁盘空间紧张时很有效但代价是下次运行项目时需要重新npm install耗时很长。一个折中的策略是在配置中区分“常驻项目”和“临时/归档项目”只清理后者的node_modules。另外使用pnpm或yarn的 PnP 特性可以从根本上减少node_modules的冗余。Maven/Gradle缓存清理Maven的本地仓库通常在~/.m2/repository。全部删除会迫使所有依赖重新下载。更精细的策略是清理长时间未访问的构件例如超过180天。使用mvn dependency:purge-local-repository命令清理特定项目的快照SNAPSHOT版本。对于Gradle可以清理~/.gradle/caches/下的非关键缓存但~/.gradle/wrapper/dists/里的Wrapper分发包如果清理了下次构建又会下载。3.2 模块二Docker系统清理Docker是资源消耗大户尤其是磁盘空间。docker system prune命令是基础但cc-cleaner可以做得更智能、更安全。核心命令与风险docker system prune删除所有已停止的容器、所有未被任何容器使用的网络、所有悬空镜像、所有构建缓存。这个命令会删除所有悬空镜像有些中间镜像可能在其他地方被引用误删可能导致后续构建变慢需要重新构建层。docker volume prune删除所有未被使用的卷。高危操作如果卷里有数据库数据等重要内容且当前没有容器挂载它它会被直接删除。docker image prune可以加-a删除所有未被容器使用的镜像或者加--filter until24h删除24小时前创建的镜像。安全的cc-cleanerDocker模块实现#!/bin/bash # 模块: docker_cleaner DRY_RUN${1:-false} # 默认为false传入 true 则为模拟运行 KEEP_IMAGES_HOURS48 # 保留最近48小时的镜像 echo [INFO] Docker 系统清理开始 (Dry Run: $DRY_RUN) # 1. 清理已停止的容器 echo - 清理已停止的容器... if [ $DRY_RUN true ]; then docker container ls -a --filter statusexited else docker container prune -f fi # 2. 清理悬空镜像未被任何镜像引用的层 echo - 清理悬空镜像... if [ $DRY_RUN true ]; then docker images -f danglingtrue else docker image prune -f fi # 3. 清理创建时间超过 KEEP_IMAGES_HOURS 且未被使用的非悬空镜像 # “未被使用”指没有被任何容器包括已停止的引用 echo - 清理旧镜像创建时间 ${KEEP_IMAGES_HOURS}小时... if [ $DRY_RUN true ]; then # 这是一个复杂的过滤dry-run 下最好列出镜像名和创建时间 docker images --format table {{.Repository}}:{{.Tag}}\t{{.CreatedAt}} | grep -v REPOSITORY | while read line; do # 这里需要解析时间并判断简化示例仅作示意 echo [DRY-RUN] 将检查镜像: $line done else # 使用 --filter 进行清理。注意until 参数在不同Docker版本中行为可能不一致生产环境需测试。 docker image prune -a -f --filter until${KEEP_IMAGES_HOURS}h fi # 4. 清理构建缓存谨慎可能影响后续构建速度 echo - 清理构建缓存... if [ $DRY_RUN true ]; then docker builder prune --filter typeexec.cachemount else docker builder prune -f fi # 5. 谨慎建议不自动清理卷或提供非常明确的确认 echo [WARN] 卷(volume)清理是高风险操作本脚本默认跳过。如需清理请手动运行 docker volume prune。注意事项Docker清理的自动化必须极其谨慎。在团队环境中一个镜像可能被其他同事的容器间接依赖。建议将Docker清理模块配置为默认仅执行低风险操作如清理已停止容器、悬空镜像对于清理旧镜像和卷要么提供非常严格的过滤条件要么只在手动确认下执行。最好将此模块的清理结果释放的空间大小、删除的镜像列表记录到日志文件供后续审计。3.3 模块三IDE与编辑器缓存清理JetBrains IDE和VSCode是两大主流它们的缓存目录固定但庞大。JetBrains IDE (IntelliJ IDEA, PyCharm, WebStorm等)缓存和索引通常位于Linux/macOS:~/.cache/JetBrains/,~/.config/JetBrains/,~/Library/Caches/JetBrains/(macOS),~/Library/Application Support/JetBrains/(macOS)Windows:%LOCALAPPDATA%\JetBrains\,%APPDATA%\JetBrains\最占空间的是index索引和caches目录。直接删除这些目录是安全的吗答案是基本安全但会带来代价。删除后重新打开项目时IDE需要重新索引整个项目这个过程可能会持续几分钟到几十分钟期间IDE会卡顿。因此清理策略应该是定期清理例如在每周五下班后自动运行清理。排除当前项目脚本可以检测当前正在运行的项目进程并跳过其对应的缓存目录。清理特定子目录可以只清理caches/下的http_client/HTTP客户端缓存或compiler/编译输出缓存而不是整个caches。VSCode清理VSCode的用户数据在Linux:~/.config/Code/macOS:~/Library/Application Support/Code/Windows:%APPDATA%\Code可以安全清理CachedData/,CachedExtensions/,Cache/等目录。同样清理后首次启动会慢一些因为需要重建缓存。实操技巧对于IDE清理最稳妥的方法不是直接rm -rf而是使用IDE自身提供的命令行工具如果存在。例如某些IDE支持--clear-caches启动参数。在缺乏官方工具时再采用删除目录的方式。务必在配置文件中让用户明确指定要清理的IDE类型和路径。3.4 模块四系统与应用日志清理日志文件如果不加管理会无限增长。cc-cleaner的日志清理模块应遵循“轮转与归档”的原则而非简单删除。实现策略基于时间的清理删除超过N天如30天或7天的旧日志文件。使用find命令配合-mtime参数。# 删除 /var/log/myapp/ 目录下超过30天的 .log 文件 find /var/log/myapp/ -name *.log -type f -mtime 30 -delete基于大小的清理当日志目录总大小超过阈值时清理最旧的日志文件直到空间低于阈值。结合 logrotate在Linux系统上logrotate是标准的日志管理工具。cc-cleaner不应替代它而是可以作为补充处理那些未被logrotate配置的、或特定应用的日志目录。压缩归档在删除前可以将旧日志压缩如用gzip后移动到归档目录既节省空间又保留审计线索。重要警告清理系统日志如/var/log/syslog,/var/log/auth.log必须格外小心。这些日志对于系统安全和故障排查至关重要。cc-cleaner的默认配置应排除这些关键的系统日志路径或者只允许清理经过非常长时间如1年以上的归档日志。最佳实践是让用户在自己的配置文件中显式地列出允许清理的日志路径模式。4. 配置驱动与安全实践cc-cleaner的威力与风险都来自于其配置。一个健壮的配置系统是项目的核心。4.1 配置文件设计示例 (YAML格式)# cc-cleaner-config.yaml dry_run: true # 默认开启模拟运行安全第一 backup_dir: /tmp/cc-cleaner-backup # 删除前备份到此目录可选 log_file: /var/log/cc-cleaner.log modules: npm_cleaner: enabled: true clean_global_cache: false # 是否清理 ~/.npm project_roots: # 扫描这些目录下的 node_modules - /home/user/projects/experimental - /home/user/projects/archived exclude_projects: # 排除这些特定项目 - /home/user/projects/current-important docker_cleaner: enabled: true remove_stopped_containers: true remove_dangling_images: true remove_unused_images_older_than_hours: 168 # 一周 remove_build_cache: false # 构建缓存清理影响构建速度默认关闭 remove_unused_volumes: false # 高危默认关闭 ide_cleaner: enabled: true jetbrains: enabled: true cache_dirs: - ~/.cache/JetBrains - ~/.config/JetBrains/*/caches # 通配符支持 keep_indices_for_projects: # 保留这些项目的索引 - /home/user/projects/current-important vscode: enabled: true cache_dirs: - ~/.config/Code/Cache - ~/.config/Code/CachedData log_cleaner: enabled: true rules: - path: /var/log/myapp/*.log keep_days: 7 compress_before_delete: true - path: /home/user/.cache/*/*.log keep_days: 30 compress_before_delete: false exclude_paths: # 绝对不碰的日志 - /var/log/syslog* - /var/log/auth.log* - /var/log/kern.log*4.2 核心安全机制实现Dry Run (模拟运行) 模式这是最重要的安全阀。在此模式下脚本应遍历所有配置的规则详细列出将会被删除、压缩或移动的每一个文件/目录的完整路径并估算可释放的空间大小但不执行任何实际的文件系统写操作。执行任何清理命令前都必须检查这个全局开关。交互式确认即使关闭了 Dry Run对于高风险操作如清理Docker卷、删除超过特定大小或时间的文件脚本也应暂停并请求用户输入如[y/N]进行确认。备份机制提供一个可选的备份功能。在执行删除前先将文件移动到指定的备份目录如/tmp/cc-cleaner-backup-timestamp。这个目录可以设置保留时间由后续的清理任务或用户手动清理。这为误操作提供了“后悔药”。详尽的日志每一次运行无论是否实际删除都必须将完整的操作计划、执行结果成功/失败、影响的文件列表、释放的空间等信息写入到指定的日志文件。日志应采用可读的格式并包含时间戳和运行参数。配置文件验证在启动时对配置文件进行语法和语义验证。检查路径是否存在、时间/大小参数是否合理、排除列表是否与包含列表冲突等。5. 集成与自动化融入工作流cc-cleaner的真正价值在于自动化解放人力。5.1 本地自动化Cron Job对于个人开发机可以设置定时任务cron job在系统空闲时运行。# 编辑 crontab: crontab -e # 每周日凌晨3点以 dry-run 模式运行并将日志邮件发送给自己 0 3 * * 0 /path/to/cc-cleaner --config /path/to/config.yaml --dry-run 21 | mail -s CC-Cleaner Weekly Dry-Run Report userexample.com # 每月第一个周一的凌晨4点实际运行一次清理谨慎 0 4 1-7 * 1 [ $(date \%d) -le 7 ] /path/to/cc-cleaner --config /path/to/config.yaml --force 21 | tee -a /var/log/cc-cleaner-monthly.log提示强烈建议长期以--dry-run模式运行定时任务先观察一段时间确认清理列表符合预期后再偶尔手动执行一次真正的清理。5.2 CI/CD 流水线集成在CI/CD环境中保持构建代理Runner的磁盘空间健康至关重要。可以将cc-cleaner作为一个步骤集成到流水线中。GitLab CI:cleanup_job: stage: .post # 在流水线最后执行 script: - | # 只在特定分支如main的流水线后执行深度清理 if [[ $CI_COMMIT_BRANCH main ]]; then ./cc-cleaner --config .cleanup-config.yaml --force else # 其他分支只做轻量清理如docker悬空镜像 docker image prune -f fi rules: - if: $CI_PIPELINE_SOURCE push # 仅对代码推送触发 when: always # 无论前面成功失败都执行清理GitHub Actions:- name: Clean up workspace if: always() # 总是运行 run: | # 使用项目特定的配置文件 python3 cc_cleaner.py --config .github/cleanup-config.yaml # 报告释放的空间可以从日志中解析在这种场景下配置文件会更激进专注于清理构建过程中产生的临时文件、缓存和容器但同样要小心避免删除下次构建需要的依赖缓存如~/.m2/repository里频繁使用的依赖。5.3 常见问题排查与解决实录即使设计再完善在实际运行中也会遇到各种问题。以下是一些典型场景及排查思路问题1运行脚本后IDE变得异常卡顿索引重建缓慢。原因cc-cleaner清理了IDE的索引和缓存目录。排查检查日志文件确认ide_cleaner模块执行了哪些删除操作。核对配置文件中keep_indices_for_projects是否包含了你的当前项目路径。解决将正在活跃开发的项目路径添加到排除列表。或者调整清理策略只清理超过1个月未访问的项目缓存可通过find -atime 30实现。问题2Docker清理后某个服务的镜像不见了导致服务启动失败。原因docker_cleaner模块清理了“未被使用的镜像”但该镜像可能被其他脚本或文档间接依赖或者只是暂时没有运行中的容器。排查查看清理日志找到被删除的镜像名称和Tag。检查是否还有其他地方如docker-compose.yml, Kubernetes yaml, 部署脚本引用了该镜像。解决提高remove_unused_images_older_than_hours的阈值例如从168小时增加到720小时即30天。或者将关键的基础镜像如nginx:alpine,postgres:14加入一个“保护名单”在清理脚本中通过docker image ls过滤掉这些镜像。问题3清理后npm install或mvn compile速度明显变慢。原因包管理器的本地缓存被清空所有依赖需要从网络重新下载。排查确认npm_cleaner或对应的包管理器清理模块是否被启用。解决区分“全局缓存”和“项目依赖”。对于全局缓存如~/.npm,~/.m2/repository可以设置更长的保留时间或完全不自动清理由用户手动触发。对于项目本地的node_modules在CI环境中可以接受清理在开发机上则应谨慎。问题4脚本因“权限不足”而失败。原因尝试删除属于root用户或其他用户的文件如/var/log/下的某些日志。排查日志中会显示Permission denied错误。解决如果确实需要清理系统级目录脚本需要以合适的权限运行如使用sudo。但强烈不建议让cc-cleaner默认以root权限运行。更好的做法是将需要root权限的清理任务如系统日志轮转交给系统自带的工具如logrotatecc-cleaner只处理用户主目录下的文件。如果必须处理可以在配置中为特定路径指定运行命令的前缀如sudo_prefix: sudo并在sudoers文件中配置好精确的无密码授权。问题5Dry Run 模式列出的文件太多无法有效审查。原因配置的清理路径太宽泛如~/.cache/*。解决Dry Run 的输出应该具有层次结构并可以按模块、按目录进行汇总统计。可以实现一个--summary参数在Dry Run时只输出每个模块将要释放的空间大小和文件数量概览而不打印每一个文件路径。对于详细列表可以将其重定向到文件供需要时查阅。elexingyu/cc-cleaner这类项目的精髓不在于它提供了多少现成的清理规则而在于它建立了一个安全、可扩展、可审计的清理框架。它迫使你思考你的系统里有哪些“垃圾”定义清理的边界并以自动化的方式安全地执行。这个过程本身就是对个人或团队数字工作环境的一次深度梳理和优化。从手动零散清理到编写一个简单的脚本再到维护一个配置驱动的工具这正是运维思维和工程化思维的体现。