首页 > 解决方案 > Makefile 多行命令在 Docker 中无法正常工作

问题描述

我正在尝试从 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

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

标签: dockersedmakefilesubshell

解决方案


不幸的是,您被您的“明显”结论误导了显然,在 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) 参数和它的选项之间没有空格。在您的示例中,您添加了一个空格,这导致 sed 认为未提供SUFFIX并将下一个参数 ( '') 视为要操作的文件名。

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

使用以下之一:

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

或者

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

推荐阅读