在Makefile目标中加载生成的.env文件时为何出现permission denied?
Makefile加载.env文件触发Permission Denied的原因与解决办法
我需要在Makefile目标中重新加载环境文件,于是写了一个生成.env文件并尝试加载的示例,但运行时出现permission denied错误。已经给.env文件设置了chmod +r权限,问题还是没解决——文件能成功创建,但就是加载不了。
相关Makefile代码
ENV_FILE := .env .PHONY: create-env-file create-env-file: @echo "Generating environment file... $(ENV_FILE)" @echo "VAR1=1" > $(ENV_FILE) @echo "VAR2=2" >> $(ENV_FILE) .PHONY: load-env-file load-env-file: echo "- Reloading env file..." $(MAKE) create-env-file chmod +r $(ENV_FILE) include $(ENV_FILE) .PHONY: start start: load-env-file echo $(VAR2)
运行输出
$make start echo "- Reloading env file..." - Reloading env file... /Library/Developer/CommandLineTools/usr/bin/make create-env-file Generating environment file... .env chmod +r .env include .env make: include: Permission denied make: *** [load-env-file] Error 1
错误原因
核心问题是你在load-env-file目标的命令列表里写了include $(ENV_FILE),但**include是Makefile的内置指令,不是shell命令**。当Make执行目标里的命令时,会把每一行都当作shell命令去调用系统中的可执行程序,而你的系统中没有名为include的可执行文件,因此抛出了"Permission denied"的错误(这个报错有误导性,本质是找不到对应命令)。
解决方案
根据你需要使用变量的场景,分两种情况处理:
场景1:让Makefile本身访问.env中的变量
如果是想让Make的变量(比如$(VAR2))读取.env里的值,需要把include放在Makefile的全局范围,而非目标的命令中。若.env是动态生成的,可以用递归Make或生成后重新触发Make加载:
方案1:检查文件后全局包含
ENV_FILE := .env .PHONY: create-env-file create-env-file: @echo "Generating environment file... $(ENV_FILE)" @echo "VAR1=1" > $(ENV_FILE) @echo "VAR2=2" >> $(ENV_FILE) # 若.env已存在则包含它 ifneq ($(wildcard $(ENV_FILE)),) include $(ENV_FILE) endif .PHONY: start start: create-env-file @$(MAKE) --no-print-directory print-var .PHONY: print-var print-var: echo $(VAR2)
方案2:递归调用Make加载变量
ENV_FILE := .env .PHONY: create-env-file create-env-file: @echo "Generating environment file... $(ENV_FILE)" @echo "VAR1=1" > $(ENV_FILE) @echo "VAR2=2" >> $(ENV_FILE) .PHONY: start start: $(MAKE) create-env-file $(MAKE) print-var # 全局包含.env,递归调用时Make会加载已生成的文件 include $(ENV_FILE) .PHONY: print-var print-var: echo $(VAR2)
场景2:让shell命令访问.env中的变量
如果只是想在目标的shell命令中使用.env里的环境变量(比如echo $VAR2),可以用source(或.)命令加载.env,注意要在同一个shell进程中执行:
ENV_FILE := .env .PHONY: create-env-file create-env-file: @echo "Generating environment file... $(ENV_FILE)" @echo "VAR1=1" > $(ENV_FILE) @echo "VAR2=2" >> $(ENV_FILE) .PHONY: load-env-file load-env-file: create-env-file echo "- Reloading env file..." # 在同一shell中加载环境变量并执行命令 . $(ENV_FILE) && echo $$VAR2 .PHONY: start start: load-env-file # 若要在start的命令中使用,同样需要source . $(ENV_FILE) && echo $$VAR2
注意:这里用$$VAR2是因为Make会把单个$解析为Make变量,需要转义成$$让shell识别为shell变量。
内容的提问来源于stack exchange,提问作者Marco
相关产品推荐
相关产品推荐

