通过 Makefile 将命令发送到 shell

通过 Makefile 将命令发送到 shell

我正在构建一个Makefile自动启动 docker 的程序osx

在启动结束时,docker 需要在 shell 上启动此命令才能配置 shell:eval "$(docker-machine env dev)"

问题是,如果我尝试在 Makefile 上运行它,这对 shell 没有影响。
事实上,如果启动:
make start然后make status我从 docker 收到错误。

这是我的 Makefile:

CURRENT_DIRECTORY := $(shell pwd)

start:
    @sh run.sh -d
    @eval $(docker-machine env dev)

start-compose:
    @docker-compose up -d

clean:
    @docker-compose rm --force

stop:
    @docker-compose stop

shutdown:
    @docker-compose stop
    @docker-machine stop dev

build:
    @docker-compose build

status:
    @docker-compose ps

cli:
    @docker-compose run --rm web bash

log:
    @docker-compose logs web

logall:
    @docker-compose logs

restart:
    @docker-compose stop web
    @docker-compose start web

restartall:
    @docker-compose stop
    @docker-compose start

.PHONY: clean start start-compose stop status shutdown build cli log logall restart restartall

有没有办法eval "$(docker-machine env dev)"在 Makefile 上启动命令并且会影响 shell?

答案1

  1. 如果您没有要跟踪的依赖项,Make 可能不是合适的工具。

  2. Make 为每个命令(或某些版本中的每个规则)启动一个 shell,如果您需要配置 shell,则需要配置每个实例。

  3. 进程不可能修改其父进程。因此,如果您想让 Make 修改执行它的 shell,那么如果不使用与 docker 相同的技巧,这是不可能的。

  4. 正如$Make 所解释的,要将其传递到 shell,需要对其进行转义。

  5. 这是一个可行的结构(请注意,我将规则合并到一个命令中),但我再次认为 Make 不是处理此类事情的正确工具,而且我对 docker 一无所知,所以我可能会错过一些相关的东西。

    start:
        @sh run.sh -d; \
        echo $$(docker-machine env dev) > ./docker-config
    
    start-compose:
        @eval $$(cat ./docker-config); \
        docker-compose up -d
    
    clean:
        @eval $$(cat ./docker-config); \
        docker-compose rm --force
    
    stop:
        @eval $$(cat ./docker-config); \
        docker-compose stop
    
    shutdown:
        @eval $$(cat ./docker-config); \
        docker-compose stop ; \
        docker-machine stop dev
    

答案2

如果我理解这个问题,您希望 make 使用某些环境配置 shell,以便当 make 退出时,该环境仍然存在。

eval命令所做的是更改当前 shell,但由于您是从 make 运行它,因此它仅更改由 make 创建的子 shell,然后在调用 `eval 的 make 目标完成时销毁该子 shell。

make 被告知要运行的每一行实际上都是在它创建的 shell 中调用的。一旦从 make 返回运行的命令,该 shell 以及您在其中所做的任何更改都会消失。

您需要做的是eval在用于调用docker命令的 shell 中运行命令,所有操作都在同一个子 shell 中。那是,每一个需要此环境的目标运行的命令需要eval首先调用该命令。并且您必须在同一个 shell 中运行命令,而不是为每一行运行单独的子 shell。

最简单的方法是将命令串在一起,;以便它首先设置环境,然后运行一些 docker 命令:

status:
    eval $$(docker-machine env dev); docker-compose ps

请注意双美元符号:$是 make 中的特殊字符,您需要将其转义,$$以便 shell 看到$

这是特定于制造商的版本这个答案。因此,您还可以调用脚本、我们&&或您喜欢的任何其他内容。

或者,如果 docker 环境不是通过 make 配置或更改的(例如,您不需要根据 make 运行时变量调整环境),而是预先确定的,则可以在已设置 docker 环境的 shell 中运行 make 。那么它的每个子shell也会有相同的环境。

您使用的 make 中有某种方法可以将多行收集到同一个子 shell 中;检查你的文档。

答案3

我解决了

@eval $$(docker-machine env dev); \
docker-compose stop; \
docker-machine stop dev

在每个 make 命令中。

相关内容