1

I want to create a multiline file with Make, having exact content:

#!/bin/bash

if [ "$JAVA_HOME" = "" ]; then echo "Please set JAVA_HOME"; exit 1; fi
export CONFIG_VARS=$( cat <<EOF
 -Dmapred.job.tracker=$JT
EOF
)

${HADOOP_HOME}/bin/hadoop $1 $HADOOP_CONFIG_VARS ${*:2} 2>&1 | grep -v SLF4J

How can I tell make to output a file with this exact content somewhere?

I tried this:

define SCRIPT_CONTENT
#!/bin/bash

if [ "$JAVA_HOME" = "" ]; then echo "Please set JAVA_HOME"; exit 1; fi
export CONFIG_VARS=$( cat <<EOF
 -Dmapred.job.tracker=$JT
EOF
)

${HADOOP_HOME}/bin/hadoop $1 $HADOOP_CONFIG_VARS ${*:2} 2>&1 | grep -v SLF4J
endef
export SCRIPT_CONTENT
bin/script:
    @echo "$$SCRIPT_CONTENT" > bin/script

This paricular solution 1) wipes $ and first char after $-es and 2) is ugly because the definition should happen outside of the particular target where it's needed :(

I also tried this:

bin/script:
    @echo '
    #!/bin/bash

    if [ "$JAVA_HOME" = "" ]; then echo "Please set JAVA_HOME"; exit 1; fi
    export CONFIG_VARS=$( cat <<EOF
     -Dmapred.job.tracker=$JT
    EOF
    )

    ${HADOOP_HOME}/bin/hadoop $1 $HADOOP_CONFIG_VARS ${*:2} 2>&1 | grep -v SLF4J
    ' > bin/script

This returns error when in make, works outside of make...

Any suggestion is very welcome!

4

3 回答 3

3

Make 希望通过在它们前面$插入另一个字符来转义任何应该按字面意思复制的字符。$

不过,更广泛地说,您似乎正在尝试使用 Make 作为 shell 脚本的替代品。执行此操作的更惯用的方法是将内容放入可以复制到目标的源文件中,或者将其放入将其写入指定目标的脚本中。Makefile 然后只需要调用复制命令或脚本。

于 2013-09-03T15:47:25.700 回答
0

你不能在 make 中做到这一点。除了 Novelocrat 所说的之外$,还有一个事实是 make 是面向行的,并且没有任何能力生成包含换行符的命令。所有出现未转义的换行符(前面没有反斜杠)都被 make 解析为该配方行的结尾,并且每个配方行都被发送到 shell 的不同调用。如果您希望将整个命令作为单个字符串发送到同一个 shell,那么您必须转义换行符。

但是,make 将在运行命令之前删除所有反斜杠/换行符对。

在 make 中完全做到这一点的唯一可能方法是一次生成一行文件,如下所示:

bin/script:
        @echo '#!/bin/bash' > $@
        @echo 'if [ "$$JAVA_HOME" = "" ]; then echo "Please set JAVA_HOME"; exit 1; fi' >> $@
        @echo 'export CONFIG_VARS=$$( cat <<EOF' >> $@
        @echo ' -Dmapred.job.tracker=$$JT' >> $@
        @echo 'EOF' >> $@
        @echo ')' >> $@
        @echo '$${HADOOP_HOME}/bin/hadoop $$1 $$HADOOP_CONFIG_VARS $${*:2} 2>&1 | grep -v SLF4J' >> $@

正如 Novelocrat 所说,完成此操作的典型方法是将脚本文件作为单独的文件并将其复制到您想要的位置,而不是生成它。

于 2013-09-03T16:27:08.817 回答
0

这个宏伟答案的帮助下,我制作了以下内容。

# From https://stackoverflow.com/a/8316519/874188
define \n


endef
define SCRIPT_CONTENT
#!/bin/bash

if [ "$$JAVA_HOME" = "" ]; then echo "Please set JAVA_HOME"; exit 1; fi
export CONFIG_VARS=$$( cat <<EOF
 -Dmapred.job.tracker=$$JT
EOF
)

$${HADOOP_HOME}/bin/hadoop $$1 $$HADOOP_CONFIG_VARS $${*:2} 2>&1 | grep -v SLF4J
endef

bin/script:
    echo '$(subst $(\n),\n,$(SCRIPT_CONTENT))' >$@

echo在测试的时候,我发现在没有任何重定向的情况下,我需要在行尾加上分号。echo我可以推测当命令行中没有 shell 元字符时会调用一个内置函数?

另外,请注意定义不能包含任何单引号,并且所有美元符号都必须加倍。也许可以删除这些限制中的一个或另一个;我没有成功,但后来我没有花太多时间和精力。

于 2013-09-03T18:07:12.293 回答