我有一个包含多个文件的目录,其中一些文件名称中包含空格:
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)
的{{3}}表示它返回一个"以空格分隔的名称列表"但完全没有承认这引起的巨大问题。 {{1}}的{{3}}也不是。
可以解决这个问题吗?如果是这样,怎么样?重命名每个文件和目录以删除空格不是一种选择。
答案 0 :(得分:49)
错误#712表明make不处理带空格的名称。无处,永远不会。
我通过使用\
(\\
似乎是拼写错误或格式化人工制品)转义空格来找到blog post saying it's partially implemented,但是:
$(wildcard)
以外的任何功能都不起作用。$?
,$^
和$+
以及任何用户定义的变量。这反过来意味着虽然$(wildcard)
将匹配正确的文件,但无论如何您都无法解释结果。因此,使用明确或非常简单的模式规则,您可以使其工作,但除此之外,您运气不好。您将不得不寻找支持空间的其他构建系统。我不确定jam / bjam是否有,scons,waf,ant,nant和msbuild都应该有效
答案 1 :(得分:18)
GNU Make在空格分隔的文件名方面做得很差。
空格在整个单词列表中用作分隔符。
This blog post很好地总结了这种情况,但警告:它错误地使用\\而不是\
target: some\ file some\ other\ file
some\ file some\ other\ file:
echo done
您也可以使用变量,因此也可以使用
VAR := some\ file some\ other\ file
target: $(VAR)
$(VAR):
echo done
只有wildcard
功能可以识别逃逸,因此您无需花费太多痛苦就可以做任何事情。
但请不要忘记你的shell也使用空格作为分隔符。
如果我想将echo done
更改为touch $@
,我必须添加斜杠才能为我的shell转义它。
VAR := some\ file
target: $(VAR)
$(VAR):
touch $(subst \,\\,$@)
或更可能使用引号
VAR := some\ file some\ other\ file
target: $(VAR)
$(VAR):
touch '$@'
最后,如果你想避免很多痛苦,无论是在GNU make还是在你的shell中,都不要在你的文件名中放置空格。如果你这样做,希望Make的有限能力就足够了。
答案 2 :(得分:12)
此方法还允许使用列出的文件名(如$?
)和用户变量(即文件列表)。
在Make中处理空格的最佳方法是用空格替换其他字符。
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\ b.c c\ d.c e\ f.c
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\ b.o:
# a b.o rule commands go here...
@echo in rule: a b.o
c\ d.o:
e\ f.o:
输出
in rule: a b.o
Object files: a b.o c d.o e f.o
此信息全部来自其他人发布的blog。
大多数人似乎建议在路径中使用空格或使用Windows 8.3路径,但如果必须使用空格,则转义空格和替换有效。
答案 3 :(得分:4)
如果您愿意再多依赖shell,这会给出一个列表,该列表可以保存带空格的名称:
$(shell find | sed 's: :\\ :g')
答案 4 :(得分:1)
最初的问题是“重命名不是一种选择”,但许多评论者指出,重命名几乎是Make可以处理空间的唯一方式。我建议采用中间方式:使用Make暂时重命名文件,然后重命名。这为您提供了使用隐式规则和其他优点的Make的所有功能,但不会弄乱您的文件命名方案。
# 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更难阅读和调试。我放弃了它,因为它让我对隐含的规则感到愤怒:%.wav : %.ogg ; oggdec "$<"
。]
答案 5 :(得分:-1)
其他答案已经很好地解决了这个问题。我只是举了一个例子来说明\
转义也适用于依赖项。
$ make --version
GNU Make 4.0
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ sed 's/^ /\t/' >Makefile <<'_EOF_'
X = $(shell find -name 'x*' -type f | sed 's/ /\\ /g')
all: $(X)
head $(X)
_EOF_
$ touch 'x 1'
$ touch 'x 2'
$ make
head ./x\ 2 ./x\ 1
==> ./x 2 <==
==> ./x 1 <==
$