Ubuntu 22.04下Makefile执行go命令权限拒绝问题排查
问题分析与解答
1. 直接运行go命令与Makefile run目标执行的差异原因
直接在bash中运行go run .时,bash会使用当前交互式会话的PATH环境变量,该PATH包含Go二进制文件的所在目录,因此能正常找到并执行go命令。
而Make执行run目标的单条命令go run .时,会尝试直接调用exec系统调用执行命令(不通过shell),此时Make使用的PATH环境变量未包含Go的安装路径,导致系统找不到go可执行文件,最终报出"Permission denied"(Error 127是命令未找到的典型错误码,这里的权限提示属于误导性的报错信息)。
2. run与run2目标执行结果不同的原因
Make的命令执行逻辑存在关键区别:
- 当命令行不包含shell元字符(如分号
;、管道|、重定向>等)时,Make会跳过shell,直接执行命令程序。run目标的go run .属于这种情况,因无特殊字符,Make直接查找go程序失败,触发报错。 - 当命令行包含shell元字符时,Make会调用系统默认shell(Ubuntu上为
/bin/sh)执行整个命令行。run2目标的命令包含分号;,属于shell元字符,因此Make会启动shell,而shell会继承当前会话的PATH(包含Go路径),从而能正常找到并执行go命令。
验证与解决方法
可以通过以下方式修复run目标的问题:
- 显式传递当前会话的
PATH:
run: env PATH=$(PATH) go run .
- 强制通过shell执行命令:
run: sh -c "go run ."
- 在Makefile开头指定shell并设置正确PATH:
SHELL := /bin/bash PATH := $(PATH) run: go run .
内容的提问来源于stack exchange,提问作者Kasper Middelboe Petersen
相关产品推荐
相关产品推荐

