为什么我需要“ \ $$(变量)”而不是“ $$(变量)”才能获得“ $(变量)”?

问题描述 投票:0回答:1
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)"字符串,而不是变量值。

我尝试了几种组合:

  1. new_contents = "$(cooly)",给出变量值,The subdirectory can see me!
  2. [new_contents = "$$",给出$
  3. [new_contents = "\$(cooly)",给出Syntax error: Unterminated quoted string错误

为什么new_contents = "$$(cooly)"不给出"$(cooly)",却什么也没得到?

["$$"-> "$",那么为什么不"$$(cooly)" ---> "$(cooly)"

makefile
1个回答
3
投票

您必须了解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!""(因为引号在两个变量中,而且引号也不是特殊的:引号与ab)。结果将是:

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构造很有帮助。
© www.soinside.com 2019 - 2024. All rights reserved.