新手应从解决具体小问题的命令行工具起步,掌握main函数、标准库调用和编译即可;首选输入固定、输出明确的场景,如封装常用shell命令;注意路径陷阱,用os.Executable()和filepath.Join确保跨平台兼容;添加-h、-v和上下文错误提示提升实用性。

go 新手做工具类项目,关键不是先学完所有语法,而是从一个「能立刻跑起来、解决具体小问题」的命令行工具开始。只要会写 main 函数、调用标准库、编译成单个二进制,就已经具备开发实用工具的能力。
怎么选第一个工具项目?盯住你每天重复敲的 shell 命令
新手最容易卡在“不知道做什么”,其实答案就在终端历史里。比如你经常手动执行:find . -name "*.log" -mtime +7 -delete,那就可以做一个 logclean 工具;又或者总要 curl -s https://api.ipify.org 查本机公网 IP,就能封装成 myip。
- 优先选「输入固定、输出明确、不依赖外部服务」的场景,避开 Web、数据库、并发调度等复杂模块
- 用
os.Args解析参数,比引入flag或cobra更快看到结果(等跑通再升级) - 第一版不处理错误细节,用
log.Fatal(err)直接退出,聚焦逻辑主干
文件操作类工具必须注意的三个路径陷阱
很多新手写的文件遍历、批量重命名工具,在自己机器上好好的,换到同事环境就报 no such file or Directory —— 问题几乎都出在路径处理上。
-
os.Stat("config.yaml")默认读的是当前工作目录,不是二进制所在目录;要用os.Executable()+filepath.Dir()获取程序根路径 - 递归遍历时,
filepath.Walk传入的路径必须是绝对路径或相对于当前工作目录的相对路径;若用户用~/Downloads,得先调用user.HomeDir()展开 - windows 下路径分隔符是
,但硬写"\\"易错;一律用filepath.Join("dir", "file.txt")构造路径
如何让工具真正“实用”?加这三行就够了
一个 Go 工具能不能被长期留在 $PATH 里,不取决于它用了多少高级特性,而在于是否尊重用户习惯。
- 支持
-h/--help:哪怕只是用fmt.Println打印三行说明,也比没强 - 支持
-v输出版本:var version = "v0.1.0",编译时用-ldflags "-X main.version=v0.2.0"注入 - 错误信息带上下文:不要只写
fmt.Println(err),改成fmt.printf("failed to read %s: %vn", filename, err)
package main import ( "fmt" "log" "os" "path/filepath" ) func main() { if len(os.Args) < 2 { fmt.Println("usage: cleanup ") os.Exit(1) } root := os.Args[1] err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() || !strings.HasSuffix(info.Name(), ".tmp") { return nil } fmt.Printf("removing %sn", path) return os.Remove(path) }) if err != nil { log.Fatal(err) } }
工具的价值不在代码多漂亮,而在你下次伸手去敲命令时,它刚好就在那里——而且没出错。