在 Makefile 中使用
.env
的最佳方法是什么,即加载该文件并导出 make
中子 shell 的所有变量?
如果所提出的解决方案仅适用于
make
,那就太好了,例如不使用任何第三方工具。另外 .env
文件支持多行变量,例如:
FOO="this\nis\na\nmultiline\nvar"
这就是为什么这个解决方案可能不够。
Make 不提供任何将文件内容读取到某个变量的方法。所以,我认为不使用外部工具是不可能达到这个结果的。但是,如果我错了,我很乐意学习一些新技巧。
因此,我们假设有两个文件,
.env
,是技术上正确的 shell 文件:
FOO=bar
BAR="notfoo" # comment
#comment
MULTILINE="This\nis\nSparta!"
# comment
和
script.sh
:
#!/bin/bash
echo FOO=${FOO}
echo BAR=${BAR}
echo -e ${MULTILINE}
一种解决方案是包含
.env
文件,然后确保导出变量:
include .env
$(eval export $(shell sed -ne 's/ *#.*$$//; /./ s/=.*$$// p' .env))
all:
./script.sh
由于 shell 和 make 对引号的处理不同,您将在输出中看到引号。
您可以通过 make 重新处理变量来避免这种情况:
include .env
VARS:=$(shell sed -ne 's/ *\#.*$$//; /./ s/=.*$$// p' .env )
$(foreach v,$(VARS),$(eval $(shell echo export $(v)="$($(v))")))
all:
./script.sh
但是多行变量将变成单行变量。
最后,您可以生成一个由 bash 处理的临时文件,并在运行任何命令之前获取它:
SHELL=bash
all: .env-export
. .env-export && ./script.sh
.env-export: .env
sed -ne '/^export / {p;d}; /.*=/ s/^/export / p' .env > .env-export
哦,在这种情况下,多行变量中的新行变得混乱。您需要另外引用它们。
最后,您可以使用上面的
export
命令将 sed
添加到 .env,然后执行以下操作:
SHELL=bash
%: .env-export
. .env-export && make -f secondary "$@"
发现了这个,效果很好:
在 makefile 顶部
ifneq (,$(wildcard ./.env))
include .env
export
endif
然后你为所有环境创建变量,例如 MY_VAR 用作 $(MY_VAR)
您可以通过创建一个函数和目标来为每个目标加载特定的 .env 文件,以便在必要时将其与其他目标一起使用。作为示例:
define setup_env
$(eval ENV_FILE := $(1).env)
@echo " - setup env $(ENV_FILE)"
$(eval include $(1).env)
$(eval export)
endef
devEnv:
$(call setup_env, dev)
prodEnv:
$(call setup_env, prod)
clean:
rm -rf bin/
build: clean
GOOS=linux GOARCH=amd64 go build -o bin/ ./cmd/...
dev: build devEnv
cd cmd/api && ./../../bin/api
migrate-dev-db: devEnv
sh +x database/migration/migrate.sh dev
migrate-prod-db: prodEnv
sh +x database/migration/migrate.sh
deploy: prodEnv
sh +x script/deployment/production/ec2-deploy.sh
这是 .env 和 makefile 用法示例:
.env
:
DATABASE_URL=postgres://postgres:[email protected]:5432/my_db_development?sslmode=disable
makefile
:
include .env
migrate:
migrate -source file://postgres/migrations \
-database $(DATABASE_URL) up
我遇到了同样的问题,这里是我如何解决它的。
.env
文件是否存在,否则
include
将引发异常。.env-example
文件添加到您的存储库中。 ENVFILE = .env
ENVFILE_EXAMPLE = .env-example
# Create the .env file if not exit.
ifeq ("$(wildcard $(ENVFILE))","")
$(shell cp $(ENVFILE_EXAMPLE) $(ENVFILE))
endif
# Load the environment variables from .env file
include $(ENVFILE)
export $(shell sed '/^\#/d; s/=.*//' $(ENVFILE))
仅供参考:这种方法也可以处理注释,默认情况下 Makefile 语法不应该这样做。
桑霍伊 - 谢谢
如果您愿意使用外部工具,您可以尝试direnv。
direnv allow .
我用这个来测试
生成文件:
all:
echo "Hello ${FOO}"
.env:
FOO=alex
~/.config/direnv/direnv.toml:
load_dotenv=true