Makefile 子 shell 中的 Bash 变量替换

Makefile 子 shell 中的 Bash 变量替换

我的 Makefile 应该并且确实/tmp/file使用以下命令在 docker 容器中创建一个文件make test

test:   
    (cd subdirectory && docker-compose exec webserver bash -c "\
        MYTEXT=hello && \
        echo 'this is $$MYTEXT world' > /tmp/file && \
        cat /tmp/file
    ")

但这并没有按预期工作。/tmp/file有内容:

this is  world

但我希望它是

this is hello world

如何将 MYTEXT 传递给下一个命令 ( echo)?

答案1

make调用sh(默认情况下,除非您更改SHELL make变量)来解释代码(sh每行一次调用,除非您\在每行末尾使用)。

在这里,您希望将$$MYTEXTso$MYTEXT嵌入到sh代码中,但您也希望它$MYTEXT不被 that 扩展sh,而是在代码中传递bash,因此必须使用\双引号内部或使用单引号来防止扩展双引号。无论如何,由于您想要bash扩展该$MYTEXT,因此您不希望$MYTEXTbash代码中使用单引号。

所以:

test:   
    (cd subdirectory && \
      docker-compose exec webserver bash -c '\
        MYTEXT=hello && \
        echo "this is $$MYTEXT world" > /tmp/file && \
        cat /tmp/file \
      '\
    )

如果你运行strace -s999 -fe execve make,你会看到(这里用docker-compose exec webserver bash替换bash):

[pid 22370] execve("/bin/sh", ["/bin/sh", "-c", "(cd subdirectory && \\\n  exec bash -c '\\\n    MYTEXT=hello && \\\n    echo \"this is $MYTEXT world\" > /tmp/file && \\\n    cat /tmp/file \\\n  '\\\n)"], 0x555ce503e620 /* 52 vars */) = 0
strace: Process 22371 attached
[pid 22371] execve("/bin/bash", ["bash", "-c", "\\\n    MYTEXT=hello && \\\n    echo \"this is $MYTEXT world\" > /tmp/file && \\\n    cat /tmp/file \\\n  "], 0x563430f3e8f8 /* 52 vars */) = 0
[pid 22371] execve("/bin/cat", ["cat", "/tmp/file"], 0x55e9509edc10 /* 52 vars */) = 0
this is hello world

无论如何,子 shell(...)在这里都不是必需的,因为cd它只会更改运行该调用的一个进程的工作目录sh,而不会影响稍后通过make运行其他命令运行的任何其他 shell 的工作目录。

答案2

获取脚本并使其在 make 之外运行。

  • 运行它shellcheck
  • 测试一下

你会发现引号有问题。

相关内容