写 Go 命令行小工具时我常用的几个习惯

平时会写一些内部用的命令行小工具,Go 是我最常用的语言:编译出来就是一个可执行文件,丢到服务器上就能跑。工具写多了,慢慢形成了几个固定的习惯,整理出来分享一下。

1. main 只负责组装,逻辑放进 run

main 函数里不写业务逻辑,只做参数解析和退出码处理,真正的逻辑放进一个返回 error 的 run 函数。这样既方便写单元测试,也不会到处散落 os.Exit。

go 复制代码
func main() {
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
	defer stop()
	if err := run(ctx, os.Args[1:]); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

2. 用 context 统一处理退出信号

上面的 signal.NotifyContext 会在收到 Ctrl+C 时取消 ctx。只要下游的 HTTP 请求、数据库查询都接收这个 ctx,按下 Ctrl+C 后工具就能干净地退出,不会留下写了一半的文件。

3. 给慢操作加超时

调用外部接口时,单独包一层超时,避免网络抖动时工具一直卡住:

go 复制代码
reqCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(reqCtx, http.MethodGet, url, nil)

4. 错误信息写给使用者看

返回错误时带上"在做什么"和关键参数,比如 fmt.Errorf("读取配置 %s 失败: %w", path, err)。用工具的人往往不看源码,一条清楚的错误信息能省掉很多来回沟通。

5. 分清 stdout 和 stderr

结果输出到 stdout,进度和日志输出到 stderr。这样别人可以放心地把结果用管道交给 jq 或 grep 处理,不会被日志混进去。

小结

这些习惯都不复杂,但坚持下来之后,工具的可维护性和使用体验都会好很多。如果你也有类似的小经验,欢迎一起交流。

相关推荐
知之则吱吱3 天前
Android 开发者验证机制迎来新变化:核心要求、实施时间与开发者应对指南
android·google
Frag0ut5 天前
Chrome数据备份指南:本地备份还原书签密码与扩展配置工具
chrome·google·谷歌浏览器·数据同步·备份工具·配置迁移·书签密码备份
GlobalAIagent5 天前
外贸站上线前的技术自查清单:漏一项询盘可能消失
google·typescript·ar·go语言·seo
知昂七昂5 天前
00-01:AOSP 源码仓库结构与 repo 工作流源码剖析(Android 16 / aosp-main)
android·google
Frag0ut8 天前
Chrome安全隐私设置指南:5个原生功能筑牢浏览器数字防线
chrome·google·谷歌浏览器·权限管理·隐私保护·安全设置·安全浏览
Frag0ut11 天前
Chrome Dev 最新功能更新:AI 智能体开发工具、HTML-in-Canvas 与双周更新节奏
chrome·google·dev·webmcp·最新功能·双周更新
Helix25012 天前
Chrome 性能优化实战:内存节省、硬件加速与 Flags 设置,让浏览器更流畅
chrome·google·性能优化·内存占用·硬件加速·设置技巧·浏览器优化
Helix25012 天前
Chrome 标签页管理术:分组、固定、搜索与恢复,告别标签页混乱
chrome·google·分组·标签页管理·固定标签·标签页恢复
Helix25013 天前
Chrome 快捷键效率提升:10 个常用快捷键,把浏览速度提升一个量级
chrome·google·浏览器·使用技巧·效率工具·快捷键·爆红教程