我正在寻找如何从Makefile环境变量中导出要在用户环境中公开的变量,因此应该可以从用户外壳程序中访问从Makefile中导出这些变量。
我尝试过make's export
,但据我了解并尝试过,它不会导出到Makefile外部。
这样做的想法是用一种优雅的方式填充Docker Compose environment variables,并使这些变量也可以在用户shell中使用。
这是我尝试使用make export
的片段:
include docker.env
export $(shell sed -n '/=/p' docker.env)
SHELL := /bin/bash
run:
@docker-compose -f my-service.yml up -d
答案 0 :(得分:1)
EDIT 在OP在注释中解释了他希望为 any 用户shell定义环境变量之后,完全重新设计了答案。
如果您的目标是为 any 用户外壳程序定义一组环境变量(我认为这是交互式外壳程序),则只需将这些定义添加到外壳程序的启动文件({{1 }}(用于bash)。从GNU制作手册:
make中的变量可以来自运行make的环境。 make在启动时看到的每个环境变量都是 转换为具有相同名称和值的make变量。 但是,在makefile中或使用命令进行显式分配 参数,覆盖环境。 (如果指定了“ -e”标志, 然后来自环境的值将覆盖makefile中的分配。 请参阅选项摘要。但这不是推荐的做法。)
示例:
.bashrc
如果要将这些定义分开,则可以仅从$ cat .bashrc
...
export FOOBAR=foobar
export BARFOO="bar foo"
...
$ cat Makefile
all:
@printf '$$(FOOBAR)=%s\n' '$(FOOBAR)'
@printf 'FOOBAR='; printenv FOOBAR
@printf '$$(BARFOO)=%s\n' '$(BARFOO)'
@printf 'BARFOO='; printenv BARFOO
$ make
$(FOOBAR)=foobar
FOOBAR=foobar
$(BARFOO)=bar foo
BARFOO=bar foo
中获取文件:
.bashrc
最后,如果您不想在文件中添加$ cat docker.env
export FOOBAR=foobar
export BARFOO="bar foo"
$ cat .bashrc
...
source <some-path>/docker.env
...
bash命令,则可以在export
中解析文件:
.bashrc
当然,$ cat docker.env
FOOBAR=foobar
BARFOO="bar foo"
$ cat .bashrc
...
while read -r line; do
eval "export $$line"
done < <(sed -n '/=/p' <some-path>/docker.env)
...
文件的语法有一些限制(没有未用引号引起的特殊字符,变量名中没有空格,正确引用的值...)如果语法不兼容bash,则为是时候问另一个有关解析此特定语法并将其转换为bash兼容语法的问题了。
答案 1 :(得分:1)
根据ArchWiki,Bash的每个进程...
每个进程将其环境存储在/ proc / $ PID / environ文件中。
因此,一旦使执行source
,export
或任何其他命令来设置新的环境变量,它将仅应用于该进程。
作为解决方法,我已经在bash启动文件中编写了代码,这样一来,一旦加载了新的bash shell,这些变量便会进入全局环境:
SHELL := /bin/bash
RC := ~/.bashrc
ENV := $(shell sed -n '/=/p' docker.env)
test:
@$(foreach e,$(ENV),echo $(e) >> $(RC);) \
答案 2 :(得分:0)
没有合作伙伴,Make不能更改调用Shell的环境。当然,如果您处于控制之中,则可以 make 调用shell进行配合。
广义上,您可以用运行真实make
的shell别名或函数替换make
命令,并根据结果设置环境变量。我将继续更详细地描述实现此目标的一种方法。
您是否将此别名或函数称为make
,例如compose
完全取决于您。要包装实际的make
会稍微困难一些-在函数内部,您需要说command make
,因为仅make
会导致别名或函数递归调用自身的无限循环-所以我将演示这一点。让我们定义一个函数(别名吮吸);
make () {
# run the real make, break out on failure
command make "$@" || return
# if there is no env for us to load, we are done
test -f ./docker.env || return 0
# still here? load it
. ./docker.env
}
如果您想要更严格的控制,可以在函数中定义一个变量,然后在Makefile
内部检查是否已设置该变量。
$(ifneq '${_composing}','function_make')
$(error Need to use the wrapper function to call make)
$(endif)
如果您还没有阅读此讨论,则错误消息会令人困惑,因此可能需要改进和/或将其记录在自述文件中。您可以将上面函数中的make
行更改为
_composing='function_make' \
command make "$@" || return
语法var=value cmd args
仅在运行命令行var
的持续时间内将变量value
设置为字符串cmd args
;然后,它返回到其先前的状态(未设置或设置为其先前的值)。
对于这种特殊的构造,变量名只需要合理地唯一且对好奇的读者透明即可;并且该值也是函数和Makefile
需要达成共识的合理唯一且合理透明的字符串。
取决于最终存储在环境中的内容,如果您需要针对多个Makefile的这种机制,可能会带来复杂性。在目录a
中运行它,然后切换到类似的目录b
似乎可以工作,但是使用了a
的东西,可怜的人会期望b
的东西。 (如果您设置的变量包含路径,则相对路径可以解决此问题,但会使其他情况复杂化。)
将此扩展到类似于Ruby的rvm
或Python的virtualenv
的模型可能值得探索;它们通常会在shell提示中添加一个指示符,以提醒您当前哪个环境处于活动状态,并具有一些(非常适度的)保护措施来在当前目录和环境不一致时向您发出警告。
另一种缺陷:始终总是加载make
的硬编码docker.env
可能会在一天中产生不受欢迎的意外。也许硬编码一个特定于该钩子的不同文件名-例如.compose_post_make_hook
?然后,它可以包含类似
. ./docker.env
在此特定目录中。