
go 命令在安装 `go.tools` 等内置命令时,默认写入 `$gotooldir`(即 go 安装目录下的 `pkg/tool/`),而非用户设置的 `gopath`;该路径通常位于 `/usr/local/go/` 下,需 root 权限,因此触发 permission denied 错误。
Go 的工具链(如 cover、vet、fix、pprof 等)属于 Go 发行版的一部分,由 go install 编译后安装到 $GOTOOLDIR 目录中(本例为 /usr/local/go/pkg/tool/linux_amd64/),而非 $GOPATH/bin。这一点常被误解——GOPATH 仅控制用户代码的构建与第三方包的存放位置($GOPATH/src、$GOPATH/pkg、$GOPATH/bin),而 $GOTOOLDIR 是 Go 运行时和标准工具的“系统级安装区”,由 GOROOT 决定,不可随意迁移。
从你的 go env 输出可见:
GOROOT="/usr/local/go" GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
这说明你使用的是系统级 Go 安装(非用户本地安装),因此所有 go install 对 cmd/* 工具的操作都会尝试写入受保护路径。
✅ 正确解决方案如下(推荐顺序):
-
优先使用 go install 到 $GOPATH/bin(适用于 Go 1.16+,且推荐现代实践)
自 Go 1.16 起,go install 支持直接安装模块命令(无需 go get),且默认安装到 $GOPATH/bin(只要 GOBIN 未设置):# 确保 GOPATH/bin 在 PATH 中 export PATH="$GOPATH/bin:$PATH" # 安装 cover(注意:新版需使用新路径) go install golang.org/x/tools/cmd/cover@latest
⚠️ 注意:code.google.com/p/go.tools 已废弃,应迁移到 golang.org/x/tools(原项目已归档)。旧版 Go 1.2.1 不支持模块,但可通过 go get -u + GOBIN 绕过系统目录。
-
为旧版 Go(如 1.2.1)设置 GOBIN,避免触碰 $GOTOOLDIR
显式指定工具安装路径至用户可写目录:export GOBIN="$GOPATH/bin" mkdir -p "$GOBIN" go get -u code.google.com/p/go.tools/cmd/cover
此时 cover 将编译并安装至 /home/vagrant/repos/atlantis-router/vendor/bin/cover,完全绕过 /usr/local/go/。
不推荐方案:sudo go install
虽然能解决权限问题,但会污染系统 Go 安装,存在版本冲突与维护风险;尤其在共享环境(如 Vagrant)中易引发后续构建异常。
? 补充建议:
- 升级 Go 版本(当前稳定版 ≥ 1.22)以获得模块支持、安全修复及更清晰的工具管理机制;
- 避免直接修改 GOTOOLDIR 或 GOROOT —— 这可能导致 go build、go test 等命令无法定位核心工具,引发 exec: "compile": executable file not found 等连锁错误;
- 若需多版本 Go 管理,推荐使用 gvm 或 asdf,实现用户级隔离安装。
总结:permission denied 的本质是路径语义混淆——GOPATH ≠ 工具安装路径。正确做法是通过 GOBIN 引导工具落地用户空间,或升级至模块化 Go 生态,从根本上规避系统目录权限问题。










