Makefile 多行命令在 Docker 中无法正常工作

Makefile multiline command does not work in Docker properly

我正在尝试从 Markdown 编译 HTML。我的 makefile 看起来像:

MD = pandoc \
    --from markdown --standalone

# ...

$(MD_TARGETS):$(TARGET_DIR)/%.html: $(SOURCE_DIR)/%.md
    mkdir -p $(@D); \
    $(MD) --to html5 $< --output $@; \
    sed -i '' -e '/href="./s/\.md/\.html/g' $@

当我在本地机器上 运行 一切正常时。

当我 运行 在 Docker 中相同时,我得到以下错误:

mkdir -p /project/docs; \
pandoc --from markdown --standalone --to html5 /project/source/changelog.md --output /project/docs/changelog.html; \
sed -i '' -e '/href="./s/\.md/\.html/g' /project/docs/changelog.html
sed: can't read : No such file or directory
makefile:85: recipe for target '/project/docs/changelog.html' failed
make: *** [/project/docs/changelog.html] Error 2

随后调用 make 给出了相同的错误,但使用了另一个文件:

sed: can't read : No such file or directory
makefile:85: recipe for target '/project/docs/todo.html' failed

显然,make 会在 HTML 完成之前以某种方式尝试 sed。 但是我使用 make 的多行语法 ; \ 以避免使用 subshel​​l。 我也试过 && \ 但它们都不起作用。我该怎么办?

不幸的是,您被您的 "obvious" 结论误导了 显然,在 HTML 完成之前以某种方式尝试 sed :) 这根本不是什么问题是。更仔细地查看您的错误消息:

sed: can't read : No such file or directory

注意can't read :;那里应该有一个文件名。它应该说类似 can't read foobar: 的内容。很明显 sed 试图读取一个名为空字符串的文件。这是你的行 运行:

sed -i '' -e '/href="./s/\.md/\.html/g' /project/docs/changelog.html

这里明显的罪魁祸首是 -i 的空字符串参数。 sed 手册页将 -i 选项描述为:

   -i[SUFFIX], --in-place[=SUFFIX]

          edit files in place (makes backup if SUFFIX supplied)

请注意 (a) SUFFIX 是可选的,以及 (b) 参数及其选项之间没有 space。在您的示例中,您添加了 space,这导致 sed 认为未提供 SUFFIX 并将下一个参数 ('') 视为文件名进行手术。

我不确定为什么当您从命令行 运行 它时它会起作用:我必须假设您的命令行版本不包含空字符串,否则它不包含space 在 -i'' 之间。

使用其中之一:

sed -i'' -e '/href="./s/\.md/\.html/g' $@

sed --in-place= -e '/href="./s/\.md/\.html/g' $@