new_contents = "\$$(cooly)"
all:
mkdir -p subdir
echo $(new_contents) | sed -e 's/^ //' > subdir/makefile
@echo "---MAKEFILE CONTENTS---"
@cd subdir && cat makefile
@echo "---END MAKEFILE CONTENTS---"
#cd subdir && $(MAKE)
# Note that variables and exports. They are set/affected globally.
cooly = "The subdirectory can see me!"
export cooly
# This would nullify the line above: unexport cooly
clean:
rm -rf subdir
我想要的是"$(cooly)"
字符串,而不是变量值。
我尝试了几种组合:
new_contents = "$(cooly)"
,给出变量值,The subdirectory can see me!
new_contents = "$$"
,给出$
new_contents = "\$(cooly)"
,给出Syntax error: Unterminated quoted string
错误为什么new_contents = "$$(cooly)"
不给出"$(cooly)"
,却什么也没得到?
["$$"
-> "$"
,那么为什么不"$$(cooly)"
---> "$(cooly)"
?
您必须了解both make扩展如何工作,和 shell扩展如何工作,以便在make中编写更复杂的配方。这是因为在make扩展完make食谱后,make食谱才传递给shell。
Make几乎逐字地将配方行传递到外壳:只有一个特殊字符(不算最后的反斜杠/换行符),即$
。如果make看到$
,它将尝试将其扩展为变量引用。为了避免这种情况,您必须将其转为$$
才能从make中隐藏。
所以,让我们看一下您的makefile:
cooly = "The subdirectory can see me!" echo $(new_contents) ...
如果
new_contents
为"$(cooly)"
,make甚至在调用Shell之前,将$(cooly)
视为变量引用并对其进行扩展。因此,首先make将$(new_contents)
扩展为"$(cooly)"
,然后将其扩展为""The subdirectory can see me!""
(因为引号在两个变量中,而且引号也不是特殊的:引号与a
或b
)。结果将是:
echo ""The subdirectory can see me!""
由于无操作,外壳程序将引号引起来并回显该值(进入管道)。
如果new_contents
为"\$(cooly)"
,则该反斜杠并不意味着要进行任何操作。就像引号一样,反斜杠(除非它们在一行的末尾)不是特别的。所以make像以前一样展开,但是这次它传递给shell的命令是这样的:
是特殊的。在这里,您已对第二个引号进行了转义,因此外壳程序不会将其视为引号字符,这意味着您的命令中引号的数量为奇数,这就是为什么您会从外壳程序中看到有关非终止引号的错误。echo "\"The subdirectory can see me!""
反斜杠不是特殊的,但它们对于shell are
如果new_contents
为"$$(cooly)"
,make不会扩展变量,它会像这样传递给shell:
如果echo "$(cooly)"
但是,
$
对于外壳来说是特殊的。将其放在双引号中不会阻止shell尝试对其进行扩展。这告诉外壳程序运行命令cooly
并替换输出。几乎可以肯定没有名为cooly
的命令,因此您将向stderr收到一条错误消息(也许您没有注意到它),并且shell不会用它替换任何内容,因为它没有向stdout打印任何内容。
new_contents
为"\$$(cooly)"
,则make将不会扩展,并运行此shell命令:echo "\$(cooly)"
shell看到反斜杠并且不展开$
,而是按字面意义使用它,并且您得到想要的结果。这里有一些提示:
首先,不要在您的make变量中包含引号(除非变量包含整个shell命令,并且您需要在其中包含引号)。 Make并不在乎引号,而将引号嵌入变量中使得很难推断外壳将看到什么。
仅在配方中包括引号。
第二,请记住,由于make不在乎引号,因此它的行为与Shell WRT单引号和双引号不同。您可以在make变量周围使用单引号,以减少从外壳中转义内容的需要,而无需在make中隐藏它们。
所以,我会这样写:
new_contents = $$(cooly)
cooly = The subdirectory can see me!
all:
mkdir -p subdir
echo '$(new_contents)' | sed -e 's/^ //' > subdir/makefile
...
顺便说一句,将@
值添加到您的Makefile中直到完成并正常工作,这从来不是一个好主意。看到输出的make print(这是它发送到shell的内容),对于弄清楚您的配方是否正确以及问题是make构造还是shell构造很有帮助。