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