bash 如何正确转义 Makefile 的数据?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7654386/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 21:05:40  来源:igfitidea点击:

How do I properly escape data for a Makefile?

bashmakefileescaping

提问by Lekensteyn

I'm dynamically generating config.mkwith a bash script which will be used by a Makefile. The file is constructed with:

我正在config.mk使用将由 Makefile 使用的 bash 脚本动态生成。该文件构造为:

cat > config.mk <<CFG
SOMEVAR := $value_from_bash1
ANOTHER := $value_from_bash2
CFG

How do I ensure that the generated file really contains the contents of $value_from_bash*, and not something expanded / interpreted? I probably need to escape $to $$and \to \\, but are there other characters that needs to be escaped? Perhaps there is a special literal assignment I've not heard of?

如何确保生成的文件确实包含 的内容$value_from_bash*,而不是扩展/解释的内容?我可能需要逃避$$$\\\,但是否有其他字符转义需求?也许有一个我没有听说过的特殊文字赋值?

Spaces seems to be troublesome too:

空间似乎也很麻烦:

$ ls -1
a b
a
$ cat Makefile
f := a b
default_target:
    echo "$(firstword $(wildcard ${f}))"
$ make
a

If I use f := a\ bit works (using quotes like f := 'a b'did not work either, makefile just treats it as a regular character)

如果我使用f := a\ b它有效(使用引号f := 'a b'也不起作用,makefile 只是将其视为常规字符)

回答by Lekensteyn

Okay, it turned out that Makefiles need little escaping for itself, but the commands which are executed by the shell interpreter needto be escaped.

好的,事实证明 Makefile 本身不需要转义,但是由 shell 解释器执行的命令需要转义。

Characters which have a special meaning in Makefile and that need to be escaped are:

在 Makefile 中具有特殊含义且需要转义的字符有:

  • sharp (#, comment) becomes \#
  • dollar ($, begin of variable) becomes $$
  • 尖锐 ( #, 评论) 变成\#
  • 美元($,变量的开始)变成$$

Newlines cannot be inserted in a variable, but to avoid breaking the rest of the Makefile, prepend it with a backslash so the line break will be ignored.

不能在变量中插入换行符,但为了避免破坏 Makefile 的其余部分,在它前面加上一个反斜杠,这样换行符将被忽略。

Too bad a backslash itself cannot be escaped (\\will still be \\and not \as you might expect). This makes it not possible to put a literal slash on the end of a string as it will either eat the newline or the hash of a following comment. A space can be put on the end of the line, but that'll also be put in the variable itself.

太糟糕了,反斜杠本身无法转义(\\仍然会,\\而不是\您所期望的)。这使得无法在字符串的末尾放置文字斜杠,因为它会占用换行符或后续注释的哈希值。可以在行尾放置一个空格,但这也将放置在变量本身中。

The recipe itself is interpreted as a shell command, without any fancy escaping, so you've to escape data yourself, just imagine that you're writing a shellscript and inserting the variables from other files. The strategy here would be putting the variables between single quotes and escape only 'with '\''(close the string, insert a literal 'and start a new string). Example: mornin' allbecomes 'morning'\'' all'which is equivalent to "morning' all".

配方本身被解释为一个 shell 命令,没有任何花哨的转义,所以你必须自己转义数据,想象一下你正在编写一个 shellscript 并插入来自其他文件的变量。这里的策略是将变量放在单引号之间并仅'使用'\''(关闭字符串,插入文字'并开始一个新字符串)进行转义。示例:mornin' all变成'morning'\'' all'相当于"morning' all".

The firstword+wildcard issue is caused by the fact that filenames with spaces in them are treated as separate filenames by firstword. Furthermore, wildcardexpands escapes using \so x\ yis matches as one word, x yand not two words.

第一个单词+通配符问题是由于其中包含空格的文件名被firstword. 此外,wildcard扩展转义使用\so x\ yis 匹配作为一个词,x y而不是两个词。

回答by user541686

It seems that the fullanswer to this question is found nowhere on the internet, so I finally sat down and figured it out for the Windows case.

似乎在互联网上找不到这个问题的完整答案,所以我终于坐下来为 Windows 案例找到了答案。

Specifically, the "Windows case" refers to file names that are valid in Windows, meaning that they do notcontain the characters \, /, *, ?, ", ^, <, >, |, or line breaks. It also means \and /are both considered valid directory separators for the purposes of Make.

具体来说,“视窗案”指的是在Windows中是有效的文件名,这意味着它们包含字符\/*?"^<>|,或换行符。这也意味着\/都被认为是 Make 的有效目录分隔符。

An example will clear it up better than I can explain. Basically, if you are trying to match this file path:

一个例子会比我能解释的更清楚。基本上,如果您尝试匹配此文件路径:

Child\a$b  {'}(a.o#$@,&+=~`),[].c

Then you have to write these rules:

然后你必须写这些规则:

all: Child\a$$b\\ \\ {'}(a.o\#$$@,&+=~`),[].o

%.o: %.c
    $(CC) '$(subst ','"'"',$(subst \,,$(subst \,/,$+)))'

Stare at it for a long time and it'll sort of start making some remote sense.

盯着它看很长时间,它会开始产生一些遥远的感觉。

This works in my MSYS2 environment, so I presume it is correct.

这适用于我的 MSYS2 环境,所以我认为它是正确的。

回答by Beta

  1. I don't see how that makefile can work as you say. A pattern rule cannot be the default.
  2. You're missing a `$` in `$(wildcard ...)`, so I think you haven't posted what you're really testing.
  3. You should escape newlines too.
  1. 我不明白这个 makefile 是如何像你说的那样工作的。模式规则不能是默认值。
  2. 您在 `$(wildcard ...)` 中缺少一个 `$`,所以我认为您还没有发布您真正要测试的内容。
  3. 你也应该转义换行符。