news 2026/11/4 5:29:43

用Python+Click打造CLI-Anything:把日常任务统一收编到命令行

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用Python+Click打造CLI-Anything:把日常任务统一收编到命令行

年纪越大越懒这句话放到命令行上同样成立。我用一个叫 CLI-Anything 的私人工具体系,把过去需要在图形界面里点来点去的活儿(文件批量重命名、系统状态查看、接口调试、文本清洗、git 仓库汇总)全部压成短命令。这篇文章不是来推荐某个现成轮子的,而是把我是怎么设计这套工具、用哪些方案落地、踩了哪些坑、以及最终可以怎么复现出来的完整过程记录下来,希望给同样想把日常任务统一收编到终端的你一个可抄的参考。

1. 项目整体设计与思路拆解

1.1 为什么要把一切塞进命令行

人一天能记住的操作方式非常有限,但工作里的重复操作却无限多。我自己的触发点是有一天发现自己同时装了五个桌面工具:一个用来批量改文件名、一个看系统资源、一个发 HTTP 请求、一个做文本替换、还有一个管 git 仓库。每个工具都有俩屏幕的按钮,但真正用到的功能只有两三个。最烦的是它们之间还不能串联,改完文件名想顺手看一眼磁盘占用,得切换窗口再来一遍。

CLI-Anything 想解决的问题本质上只有一个:给高频、重复、可程序化的任务一个统一入口。命令行相比图形界面的好处不是你敲得快,而是可组合、可记录、可批量。你今天手动执行了一个命令,明天就可以把它写进脚本里,后天就能挂在定时任务上。图形界面里的操作则需要你记住人肉步骤,这是完全没法扩展的。

所以这个项目的核心设计哲学是:一切命令必须短、必须稳定、必须有返回值(能接入别的脚本)。那些需要眼睛直观看图表的场景留给专业可视化工具,但日常 80% 的操作,命令行绰绰有余。

1.2 方案选型:技术栈怎么定

选型这件事我花了整整一下午,对比过三个方向:

方案优势劣势我的判断
Python + click生态全、代码直观、psutil/requests 现成启动稍慢(约 0.3s)最终选择
Node.js + commander启动快、JSON 原生文件操作和系统调用的库不如 Python 顺手备选
Go + cobra单二进制、极快迭代成本高,日常脚本语言不够快适合发布场景

我最后选了 Python + click。原因不复杂:CLI-Anything 是给我自己用的私人工具,重点在快速开发和灵活修改,运行效率反而不是瓶颈。Python 生态里文件处理、系统监控、网络请求都有非常成熟的库,写起来像写自然语言一样流畅。而且 click 这个库天然支持命令分组、参数解析和帮助文档,几乎不用写命令行解析的样板代码。

如果你要分发给很多用户、或者放在低配服务器上高频调用,Go 会是更优解。但自己做工具,别为性能过早优化。

1.3 架构规划:命令树怎么组织

CLI-Anything 不是一把大铁锤,而是一个工具架。我按照任务领域把命令分成五个顶层分组:

cli-anything ├── file # 文件与目录批处理 ├── sys # 系统信息与进程监控 ├── text # 文本处理与格式化 ├── net # 网络请求与接口调试 └── git # git 工作流辅助

每个分组下挂若干子命令,比如file rename、sys status、text replace。这样设计的好处有三个:第一,命令不存在命名冲突,敲前缀就知道属于哪个领域;第二,每个分组都是一个 Python 模块,方便单独维护和测试;第三,shell 的 Tab 补全体验极佳,敲cli file然后按两下 Tab,你能看到这个组下所有子命令。

模块之间的公共逻辑(比如路径校验、输出格式化、颜色高亮)抽到公共包里,避免每个模块都复制粘贴一遍。

2. 核心功能模块与工具选型解析

2.1 文件与目录批处理模块

这个模块是 CLI-Anything 用得最狠的部分。功能清单包括:批量重命名(支持正则替换和模板)、重复文件检测与清理、磁盘大文件扫描、按日期归档目录。底层的库用了 Python 标准库的 pathlib 和 os,检测重复文件时用 hashlib 计算文件的哈希。

模块设计上有一个原则:所有破坏性操作必须有 dry-run 模式。file rename与file clean都默认只打印将要执行的动作,不会真的动文件。需要真实执行时加--yes或--apply。这个设计帮我避免了两次差点把备份目录清空的灾难。

批量重命名的参数设计要注意:支持新旧命名模板的正则替换还不够,最好支持占位符,比如%Y%m%d这种日期后缀,方便做归档。这类参数用 click 的字符串参数可以轻松搞定。

2.2 系统信息与进程监控模块

系统监控我在 Windows 和 Linux 两个环境都有需求。得益于 psutil 这个库,一段代码在两个平台都能跑。sys status命令输出 CPU 逻辑核心数、负载、内存占用、磁盘使用率、关键温度(如果有传感器)。sys top命令则模仿任务管理器,按照 CPU 或内存排序展示前十个进程,实时刷新。

这里有个设计细节:数值输出必须做人性化处理。直接输出字节数会得到一串天文数字,所以我写了个human_size函数,把字节自动换算成 KB/MB/GB,保留一位小数。这个函数后面被 text、net 模块反复复用,成了公共库里的明星工具。

2.3 文本处理与格式化模块

文本处理模块覆盖了批量的全局替换、编码转换、JSON 格式化与 JSONLines 摘要。日常用得最多的是text replace,它接受一个 glob 路径模式,然后把匹配文件里的旧字符串统一替换为新字符串。和文件模块一样,它默认 dry-run,打印每个文件里会命中多少次替换。

编码问题在这个模块里最常出现。GBK、UTF-8、UTF-8-BOM 混在一起的时候,直接读文件会报 UnicodeDecodeError。我的处理方式是让用户通过--encoding参数指定输入编码,同时加一个--auto模式:先尝试 UTF-8,失败后尝试 GBK,还不行就报错并输出前几个字节的十六进制,方便排查。

2.4 网络请求与接口调试模块

过去我调接口要开 Postman,环境配置、请求头管理、导出测试用例,重得很。CLI-Anything 的net模块只保留三个命令:net get、net post和net check。net get/post就是最直接的 HTTP 请求,支持自定义 header、body、超时时间。net check则用来做批量健康检查:传一组 URL,它并发地请求并统计状态码和耗时,输出一个表格。

细节上,请求时我会给所有命令加上重试次数参数(默认 2 次),并设置一个合理超时(默认 10 秒),避免网络抖动导致命令行挂死。JSON 输出时,利用 Python 的 json.dumps 做美化输出,并设置 ensure_ascii=False,避免中文 Unicode 转义。

2.5 Git 工作流辅助模块

Git 命令本身已经够简洁,为什么还要包一层?因为高频操作里有一批“组合动作”。比如批量检查多个仓库的状态、一键清理已合并的本地分支、按照固定模板快速生成规范化的 commit message。这些动作用原生命令一条条敲太碎,而写 shell 脚本又容易在环境间迁移时碰壁。

git repos命令会读取一个配置文件(里面放了你本地所有项目的绝对路径),然后逐个执行git status --short,把结果汇总到一个列表里。有未提交变更的仓库高亮显示,完全干净的仓库显示为一行简单提示。这样我早上打开电脑,跑一次就能知道所有项目的状态,省了逐个cd的功夫。

3. 实操过程:从零搭建 CLI-Anything

3.1 环境准备与依赖安装

推荐用 Python 3.10 以上版本,虚拟环境创建我用 venv:

mkdir cli-anything && cd cli-anything python -m venv .venv source .venv/bin/activate # Windows 用 .venv\Scripts\activate pip install click psutil requests

项目结构我按模块划分:

cli-anything/ ├── pyproject.toml ├── cli_anything/ │ ├── __init__.py │ ├── cli.py # 入口与分组 │ ├── common.py # 公共工具函数 │ ├── file_cmd.py # file 分组 │ ├── sys_cmd.py # sys 分组 │ ├── text_cmd.py # text 分组 │ ├── net_cmd.py # net 分组 │ └── git_cmd.py # git 分组 └── tests/

pyproject.toml 里最关键的是入口点的配置,它决定cli-anything命令怎么被安装到系统里:

[project.scripts] cli-anything = "cli_anything.cli:cli"

这样执行pip install -e .之后,就等于在自己机器上多了一个全局命令。修改代码立刻生效,不需要重新安装。

3.2 入口设计与命令注册

入口文件的核心任务是把所有分组挂载到同一个 Group 上。click 的写法非常直接:

import click from . import file_cmd, sys_cmd, text_cmd, net_cmd, git_cmd @click.group() @click.version_option("0.1.0", prog_name="cli-anything") def cli(): """CLI-Anything: 把日常任务统一收编到命令行的万能工具箱。""" for module in [file_cmd, sys_cmd, text_cmd, net_cmd, git_cmd]: if hasattr(module, "register"): module.register(cli)

每个模块文件里提供一个register(group)函数做命令注册。比如 file 模块:

import click from .common import validate_path @click.group(name="file") def file_group(): """文件与目录批处理。""" @file_group.command(name="scan") @click.argument("path", type=click.Path(exists=True)) @click.option("--min-size", default="100M", help="只显示超过该大小的文件") def scan(path, min_size): """扫描目录下的大文件。""" ... def register(group): group.add_command(file_group)

这样组织代码的原因很简单:每个模块之间不互相依赖,新增一个分组只需要新建一个 py 文件、写若干命令、实现register函数即可,其余部分不需要改动。哪怕以后拆出去给别人用,也可以整模块复制。

3.3 文件批处理命令的实现细节

以file rename为例,它的功能是:筛选出匹配正则的文件名,然后执行替换,支持 dry-run 和预览。

import re from pathlib import Path import click @click.command(name="rename") @click.argument("pattern", type=str) @click.argument("replacement", type=str) @click.option("--ext", default="*", help="文件扩展名过滤,比如 *.txt") @click.option("--recursive/--no-recursive", default=True) @click.option("--apply", is_flag=True, help="dry-run 模式下不执行实际重命名") def rename(pattern, replacement, ext, recursive, apply): """将匹配 pattern 的文件名替换为 replacement。""" base = Path.cwd() files = base.rglob(ext) if recursive else base.glob(ext) hit = 0 for f in files: if not f.is_file(): continue new_name = re.sub(pattern, replacement, f.name) if new_name != f.name: target = f.with_name(new_name) click.echo(f"{f.name} -> {new_name}") if apply: f.rename(target) hit += 1 click.echo(f"共匹配 {hit} 个文件")

--apply这个变量的命名我特意跟apply动作分开,只有你确认预览结果没问题才加上它。这里有一个经验:永远不要把破坏性操作放在默认路径上。命令行工具和图形工具不一样,图形工具你还能弹窗确认,命令行里一旦回车就没有反悔按钮。

3.4 系统监控命令的实现细节

sys status的代码要兼容 Windows 和 Linux,psutil 已经抹平了大部分差异。核心输出函数如下:

import psutil import platform def human_size(num): for unit in ["B", "KB", "MB", "GB", "TB"]: if num < 1024: return f"{num:.1f} {unit}" num /= 1024 return f"{num:.1f} PB" def sys_status(): cpu_percent = psutil.cpu_percent(interval=1) virtual_mem = psutil.virtual_memory() disk_usage = psutil.disk_usage("/") boot_time = psutil.boot_time() click.echo(f"主机: {platform.node()}") click.echo(f"系统: {platform.system()} {platform.release()}") click.echo(f"CPU 使用率: {cpu_percent}%") click.echo(f"内存: {human_size(virtual_mem.used)} / {human_size(virtual_mem.total)} " f"({virtual_mem.percent}%)") click.echo(f"磁盘 /: {human_size(disk_usage.used)} / {human_size(disk_usage.total)} " f"({disk_usage.percent}%)")

注意cpu_percent(interval=1)这个参数,官方文档特别说明第一次调用返回的是 0.0,因为需要采样时间差。如果要第一次就有准确值,可以程序启动时先调一次预热。这个细节在文档里不明显,实测中容易踩到,我一开始没预热,还以为是 psutil 的 bug。

3.5 打包发布与日常使用

开发时一直用pip install -e .,既注册命令又免安装。等到我把这套东西同步到另一台电脑时,发现一个问题:每个环境都要装一遍依赖,还要保证 Python 版本一致。偷懒的做法是用 requirements.txt:

pip freeze > requirements.txt

但这样会把项目自身的依赖和无关包全带进去,不干净。更好的做法是在 pyproject.toml 里声明项目依赖:

[project] dependencies = [ "click>=8.1", "psutil>=5.9", "requests>=2.31", ]

然后一条命令安装到新机器:

pip install -e .

日常使用我再推荐一个技巧:给 bash/zsh 加命令别名。比如alias c=cli-anything,然后把c f(f 是 file 的别名)绑到 Tab 补全上。实测下来,最终我敲命令的速度基本和敲普通 Linux 命令一样快。这个阶段才是最舒服的:工具已经长在肌肉记忆里了。

4. 常见问题与排查技巧实录

4.1 命令冲突与命名空间管理

CLI-Anything 里的命令分了很多组,组多了之后最怕命令重名。比如text replace和file rename功能上有重叠,第一次实现时我在 file 组里放了个replace,又在 text 组里放了个replace,于是 CLI 一启动就报重复命令。我的解决办法是约定:file 组只处理“名字层面”的变化,text 组只处理“内容层面”的变化。如果两个命令做的事本质相同,就统一靠前缀做区分。这个约定不仅解决了冲突,也让命令的查找路径更清晰。

4.2 路径参数与转义陷阱

命令行处理路径是一块天然的雷区。最常见的坑是路径里有空格,比如~/My Documents/项目 A。如果你在 shell 里手敲cli-anything file scan ~/My Documents/项目 A,那它会解析成三个独立参数,直接报错。解决方法是使用 Tab 补全,shell 会自动给路径加转义;如果手敲,就用引号把整个路径包起来。另一个坑是 Windows 的路径里结尾的反斜杠C:\folder\在某些解析逻辑里会被当成转义符,我在 click 的 Path 类型下遇到过,最终统一用 pathlib.PurePath 做内部表示,避免字符串拼接时出问题。

4.3 跨平台兼容与编码问题

这台工具我同时在 Windows 和 Linux 上使用,编码问题首当其冲。Windows 终端默认的代码页可能是 GBK,Linux 是 UTF-8,直接用 print 输出中文在某些环境会乱码。我自己踩过的坑是:在 PowerShell 里调用sys status,磁盘使用率那行中文显示正常,但文件名带特殊字符时终端直接中断。后来我把所有控制台输出统一处理:优先用sys.stdout.reconfigure(encoding="utf-8"),并且在文件读写时显式声明编码。还有一个经验:Windows 下避免使用colorama这类 ANSI 颜色库糊得到处都是,我就只用在 Linux/macOS 检测到终端颜色支持时才启用。

4.4 性能优化与大数据量处理

日常文件扫描不是每次都要跑几千个文件,但一旦目录里面有几十万个小文件(比如 node_modules 或者 .git 目录),速度差距就出来了。标准库的os.scandir比os.listdir+os.path.join快很多,并且它能直接拿到文件类型,省去多余的系统调用。实测在 Linux 上一个包含 30 万文件的目录,用os.scandir遍历只需要几秒钟,而os.listdir可能要 20 秒以上。另外我统一用pathlib.Path.rglob做递归匹配,它内部也基于 scandir,不会重复踩坑。

4.5 常见问题速查表

现象原因解决方案
命令安装后找不到没有配置 entry_points检查 pyproject.toml 的 [project.scripts] 段
cpu_percent第一次返回 0psutil 需要两次采样程序启动时先调用一次预热
中文输出乱码终端编码与 Python 输出不一致stdout reconfigure 为 UTF-8
文件名带空格无法解析shell 参数分割使用引号包裹或依赖 Tab 补全
运行慢,扫描目录卡顿目录里文件过多改用 os.scandir 和增量过滤
重复文件删除后误伤哈希匹配精度不够或 dry-run 未启用对破坏性操作强制先 dry-run
不同系统的路径处理错误字符串拼接路径改用 pathlib.PurePath
网络超时导致 CLI 挂起未设置 timeoutrequests 统一加 timeout=10
批量替换后文件编码异常忽略原始编码提供 --encoding 和 --auto 参数
Tab 补全失效未安装 shell 补全脚本click 支持生成补全脚本,按文档安装

写在最后:CLI-Anything 这个项目对我最大的改变不是省了多少时间,而是让我养成了一个习惯——每次发现自己重复手工操作超过两次,就会停下来想想能不能把它变成一条命令。工具本身是私人化的,每个人的高频任务不同,但设计模式是通用的:分组清晰、破坏性操作默认安全、输出可解析、参数可记忆。如果你也想做一套自己的命令行工具箱,建议从最让你烦躁的那个重复动作开始,别一上来就追求大而全。一条命令用顺手了,你自然会忍不住想加第二条。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/4 5:29:38

Python+Playwright抢票脚本实战:环境配置、元素定位与时序控制

1. 抢票脚本这件事&#xff0c;先把预期和边界聊透每年演出季一到&#xff0c;后台私信就被同一类问题刷屏&#xff1a;大麦网的票到底怎么才能抢到&#xff1f;脚本到底能不能用&#xff1f;我写这篇文章&#xff0c;不是要给你一个“一键秒杀”的神话&#xff0c;而是想把一个…

作者头像 李华
网站建设 2026/11/4 5:29:18

Codex 接入 Jev 模型服务:API Key 配置与 Skill 实战指南

1. 这套组合到底在解决什么问题第一次看到“给Codex配上Jev”这个说法&#xff0c;很多人会以为是某个新出的插件或者一键脚本。其实拆开看&#xff0c;它说的是两件事&#xff1a;Codex 作为代码智能体&#xff08;Agent&#xff09;的调度框架&#xff0c;和Jev 作为模型服务…

作者头像 李华
网站建设 2026/11/4 5:28:06

FastAPI生产级main.py设计:路由、数据库与服务启动最佳实践

1. 这不是“Hello World”&#xff0c;而是生产级 FastAPI 服务的真正起点你打开一个 FastAPI 项目&#xff0c;第一眼看到的几乎总是main.py——它短小、干净&#xff0c;甚至只有一二十行代码。但正是这个文件&#xff0c;承载着整个服务的“心脏起搏器”功能&#xff1a;它定…

作者头像 李华
网站建设 2026/11/4 5:27:50

低成本高效调用Claude API的云服务商网关方案

1. 项目背景与核心思路最近在开发者社区看到不少关于如何经济高效地使用Claude API的讨论。作为一个长期关注AI工具落地的开发者&#xff0c;我发现官方订阅方案对于个人开发者或小团队来说成本压力较大&#xff0c;特别是高频使用时账单容易失控。经过一段时间的摸索&#xff…

作者头像 李华
网站建设 2026/11/4 5:27:17

AI论文辅助系统:从选题到投稿的全流程解决方案

1. 论文写作的痛点与破局之道写论文这件事&#xff0c;从本科生到博士生都逃不过。我指导过上百位学生的论文写作&#xff0c;发现大家普遍卡在几个关键环节&#xff1a;选题找不到方向、文献综述像无头苍蝇、数据处理总出bug、格式调整能折腾一整天。更可怕的是&#xff0c;这…

作者头像 李华
网站建设 2026/11/4 5:26:10

改进鲸鱼优化算法在云计算资源调度中的应用

1. 项目背景与问题定义在云计算资源调度领域&#xff0c;虚拟机放置问题&#xff08;Virtual Machine Placement Problem, VMPP&#xff09;一直是影响数据中心能效的关键挑战。传统优化算法在处理大规模异构服务器集群时&#xff0c;常面临收敛速度慢、易陷入局部最优等瓶颈。…

作者头像 李华