【问题标题】:Makefile recipe with a here-document redirection带有此处文档重定向的 Makefile 配方
【发布时间】:2016-06-01 16:19:01
【问题描述】:

有人知道如何在食谱上使用此处文档重定向吗?

test:
  sh <<EOF
  echo I Need This
  echo To Work
  ls
  EOF

尝试使用通常的反斜杠方法(基本上以单行中的命令结束)时,我找不到任何解决方案。

理由:

我有一组多行配方,我想通过另一个命令(例如 sh、docker)进行代理。

onelinerecipe := echo l1
define twolinerecipe :=
echo l1
echo l2
endef
define threelinerecipe :=
echo l1
echo l2
echo l3
endef

# sh as proxy command and proof of concept
proxy := sh

test1:
  $(proxy) <<EOF
  $(onelinerecipe)
  EOF

test2:
  $(proxy) <<EOF
  $(twolinerecipe)
  EOF

test3:
  $(proxy) <<EOF
  $(threelinerecipe)
  EOF

我希望避免的解决方案:将多行宏转换为单行。

define threelinerecipe :=
echo l1;
echo l2;
echo l3
endef

test3:
  $(proxy) <<< "$(strip $(threelinerecipe))"

这可行(我使用 gmake 4.0 和 bash 作为 make 的外壳)但它需要更改我的食谱,而且我有很多。 Strip 从宏中删除换行符,然后所有内容都写在一行中。

我的最终目标是:proxy := docker run ...

【问题讨论】:

  • sh -c 'put your commands here'怎么样?
  • Heredoc in a Makefile?的可能重复
  • @e0k 我添加了上下文
  • 你的具体例子最好写成printf 'I need this\nTo work\n'; ls
  • @e0k 如果您仍然认为这个 Q 是重复的,请再次投票。这样它就不会老化。

标签: bash shell makefile gnu-make heredoc


【解决方案1】:

在 Makefile 中的某处使用 .ONESHELL: 行会将所有配方行发送到单个 shell 调用,您应该会发现原始 Makefile 可以正常工作。

【讨论】:

  • 重要的缺失说明:它的影响是全局的,而不是单个规则和配方的局部。如果它出现在 makefile 中的任何位置,那么 all 配方行 for each 目标将被提供给 shell 的单个调用。就我而言,它不会带来问题。但也请注意,.SHELLFLAGS = -ec 需要保持默认的 make 错误退出行为。
  • 我已经使用这个解决方案几天了,到目前为止我唯一的缺点是回显问题。因为使用.ONESHELL:,前导@ 现在对整个配方有效。这使得选择性回显(回显一个命令而不是另一个命令)不再可能。要解决这个问题,您只能更改您的配方,从而打破我一直在寻找的规则:透明代理。无论如何,这是唯一允许 here-doc 的解决方案,所以我正在验证它。
【解决方案2】:

make 在配方中看到多行块时 (即,除了最后一行之外,所有行都以\ 结尾), 它将未修改的块传递给外壳。 这通常适用于 bash, 除了这里的文档。

解决此问题的一种方法是删除任何尾随\s, 然后将生成的字符串传递给 basheval。 您可以在 make 中通过使用${.SHELLFLAGS}${SHELL} 来做到这一点。 如果您只希望它针对少数目标发挥作用,则可以以特定于目标的形式使用这两种方法。

.PHONY: heredoc

heredoc: .SHELLFLAGS = -c eval
heredoc: SHELL = bash -c 'eval "$${@//\\\\/}"'

heredoc:
    @echo First
    @cat <<-there \
        here line1 \
        here anotherline \
    there
    @echo Last

给予

$ make
First
here line1
here anotherline
Last

尤金,请小心那句话。 注意这里的作弊: 我正在删除所有反斜杠, 不仅仅是线路末端的那些。 YMMV。

【讨论】:

  • 特别感谢“当 make 在配方中看到一个多行块时(即,除最后一个以外的所有行都以 \ 结尾的块)时,它会通过该块 un-修改为外壳。”位:我尝试过使用here-doc,仅通过该技术即可解决。
【解决方案3】:

使用 GNU make,您可以将 multi-line variablesexport 指令结合使用多行命令,而无需全局打开 .ONESHELL

export define script
cat <<'EOF'
here document in multi-line shell snippet
called from the "$@" target
EOF
endef

run:; @ eval "$$script"

会给

here document in multi-line shell snippet
called from the "run" target

你也可以把它和value函数结合起来,防止它的值被make扩展:

define _script
cat <<EOF
SHELL var expanded by the shell to $SHELL, pid is $$
EOF
endef
export script = $(value _script)

run:; @ eval "$$script"

会给

SHELL var expanded by the shell to /bin/sh, pid is 12712

【讨论】:

    【解决方案4】:

    不是 here 文档,但这可能是一个有用的解决方法。 而且它不需要任何 GNU Make 主义。 将这些行放在带有括号的子shell中,在每行前面加上 echo。 在适当的情况下,您需要尾随 sloshes 和分号和 slosh。

    test:
    ( \
        echo echo I Need This ;\
        echo echo To Work ;\
        echo ls \
    ) \
    | sh
    

    【讨论】:

      猜你喜欢
      • 2016-04-04
      • 2017-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-25
      • 2018-02-09
      • 2015-05-03
      • 1970-01-01
      相关资源
      最近更新 更多