GNU可以使用空格处理文件名吗?

我有一个目录包含几个文件,其中一些名称中有空格:

Test workspace/ Another directory/ file1.ext file2.ext demo 2012-03-23.odp 

我在这个目录上使用GNU的$(wildcard)命令,然后使用$(foreach)遍历结果,打印出所有内容。 代码如下:

 FOO := $(wildcard *) $(info FOO = $(FOO)) $(foreach PLACE,$(FOO),$(info PLACE = $(PLACE))) 

以下是我期望看到的内容:

 Test workspace Another directory file1.ext file2.ext demo 2012-03-23.odp 

这是我实际得到的:

 Test workspace Another directory file1.ext file2.ext demo 2012-03-23.odp 

后者显然对我没有用处。 $(wildcard)的文档说明它返回一个“空格分隔的名称列表”,但是完全不能确认这个引发的巨大问题。 $(foreach)的文档也没有。

可以解决这个问题吗? 如果是这样,怎么样? 重命名每个文件和目录以删除空格不是一个选项。

错误#712表明make不处理带有空格的名字。 没有,从来没有。

我发现一篇博客文章说这是通过用\\\似乎是排字错误或格式化工件)逃避空间来部分实现的,但是:

  • 除了$(wildcard)之外,它在任何函数中都不起作用。
  • 从variables中扩展名称列表不起作用,其中包括特殊variables$?$^$+以及任何用户定义的variables。 这又意味着$(wildcard)将匹配正确的文件,而无论如何您将无法解释结果。

所以用明确的或者非常简单的模式规则就可以使其工作,但除此之外,你是不走运的。 你将不得不寻找其他支持空间的构build系统。 我不确定jam / bjam , scons , waf , ant , nant和msbuild是否都可以工作。

GNU Make与空格分隔的文件名差别很大。

空格在整个地方的单词列表中用作分隔符。

这篇博文总结了这种情况,但警告:它不正确地使用\\而不是\

 target: some\ file some\ other\ file some\ file some\ other\ file: echo done 

你也可以使用variables,所以这也可以

 VAR := some\ file some\ other\ file target: $(VAR) $(VAR): echo done 

只有wildcard函数才能识别转义,所以你不能做任何奇怪的事情而没有太多的痛苦。


但是别忘了你的shell也使用空格作为分隔符

如果我想要改变touch $@ ,我必须添加斜线才能将其转义。

 VAR := some\ file target: $(VAR) $(VAR): touch $(subst \,\\,$@) 

或者更可能使用引号

 VAR := some\ file some\ other\ file target: $(VAR) $(VAR): touch '$@' 

最后,如果你想避免很多痛苦,无论是在GNU make和shell中,都不要在你的文件名中加空格。 如果你这样做,希望Make的有限function就足够了。

这个方法也允许使用列出的文件名,如$? 和用户variables是文件列表。

在Make中处理空格的最好方法是用空格replace其他字符。

 s+ = $(subst \ ,+,$1) +s = $(subst +,\ ,$1) $(call s+,foo bar): $(call s+,bar baz) $(call s+,bar\ baz2) # Will also shows list of dependencies with spaces. @echo Making $(call +s,$@) from $(call +s,$?) $(call s+,bar\ baz): @echo Making $(call +s,$@) $(call s+,bar\ baz2): @echo Making $(call +s,$@) 

输出

 Making bar baz Making bar baz2 Making foo bar from bar baz bar baz2 

然后,您可以使用所有GNU Make函数安全地处理文件名列表。 只要确保在规则中使用这些名称之前删除了+。

 SRCS := a\ bc c\ dc e\ fc SRCS := $(call s+,$(SRCS)) # Can manipulate list with substituted spaces OBJS := $(SRCS:.c=.o) # Rule that has object files as dependencies. exampleRule:$(call +s,$(OBJS)) # You can now use the list of OBJS (spaces are converted back). @echo Object files: $(call +s,$(OBJS)) a\ bo: # a bo rule commands go here... @echo in rule: a bo c\ do: e\ fo: 

输出

 in rule: a bo Object files: a bo c do e fo 

这个信息全部来自其他人发布的博客 。

大多数人似乎build议使用path或使用Windows 8.3path中没有空格,但如果您必须使用空格,转义空格和replace作品。

如果你愿意依靠你的shell多一点,这给了一个列表,可以用空格保存名称就好了:

 $(shell find | sed 's: :\\ :g') 

原来的问题说“重命名不是一个选项”,但许多评论者指出,重命名是Make只能处理空间的唯一方法。 我build议一个中间的方法:使用Make临时重命名文件,然后重新命名它们。 这给了你隐含的规则和其他善意的所有权力,但不会弄乱你的文件命名scheme。

 # Make cannot handle spaces in filenames, so temporarily rename them nospaces: rename -v 's/ /%20/g' *\ * # After Make is done, rename files back to having spaces yesspaces: rename -v 's/%20/ /g' *%20* 

你可以通过make nospaces来手动调用这些目标, make yesspaces ,或者你可以有其他的目标依赖于它们。 例如,您可能希望有一个“推送”目标,确保在将文件与服务器同步之前将空格放回到文件名中:

 # Put spaces back in filenames before uploading push: yesspaces git push 

[旁注:我尝试了使用+ss+的答案,但是这使得我的Makefile更难于读取和debugging。 我放弃了它,当它给了我隐含的规则如: %.wav : %.ogg ; oggdec "$<" %.wav : %.ogg ; oggdec "$<" 。]