GNU可以使句柄文件名带有空格吗?


78

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

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

$(wildcard)在此目录上使用GNU的命令,然后使用遍历结果$(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)

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

Answers:


57

错误#712提示make不处理带空格的名称。无处,永远不会。

我找到了一篇博客文章,说它的部分实现是通过将空格转义为\\\似乎是拼写错误或格式化伪像),但是:

  • 除了以外,它无法在任何功能中使用$(wildcard)
  • 从变量扩展名列表时,包括特殊变量,它不工作$?$^$+以及任何用户定义的变量。反过来,这意味着虽然$(wildcard)将匹配正确的文件,但是您将始终无法解释结果。

因此,使用显式或非常简单的模式规则,您可以使其正常运行,但除此之外,您还不走运。您将不得不寻找其他支持空间的构建系统。我不确定jam / bjamsconswafantnantmsbuild是否都可以正常工作。


我能够得到$?$@。如果您有兴趣,请在下面查看我的答案。路易(Louis)是错的,它确实有效。随时自己进行测试
Mr_Moneybags 2015年

20

GNU Make在使用空格分隔的文件名方面做得很差。

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

这篇博文很好地总结了这种情况,但是警告:它错误地使用了\\而不是\

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函数可以识别转义,因此,如果没有很多痛苦,您将无法做任何幻想。


但不要忘记,您的外壳也使用空格作为分隔符

如果要将更改echo donetouch $@,则必须添加斜杠以将其转义给我的shell。

VAR := some\ file

target: $(VAR)

$(VAR):
    touch $(subst \,\\,$@)

或者更可能使用引号

VAR := some\ file some\ other\ file

target: $(VAR)

$(VAR):
    touch '$@'

最后,如果要避免很多麻烦,无论是在GNU make中还是在shell中,请不要在文件名中添加空格。如果这样做,希望Make的有限功能就足够了。


4
“不要在文件名中添加空格”:我从不这样做。但有时你必须写一个make文件,与别人作品的源代码....
火星

@火星,我明白了。只是为痛苦做准备。
Paul Draper

保罗,别开玩笑。我想我花了几个小时尝试不同的事情。我试图通过文件的存在来测试版本。我放弃。现在每个人都必须使用相同的版本。(就我而言,这并不难,但这是一个微妙的解决方案。)
Mars

幸运的是,您仍然可以使用$(shell ...)它进行初始操作。
o11c

1
我正在使用WSL,所以我在Windows上拥有所有的Linux工具...。我的所有二进制文件都位于“程序文件”中。大aa
Brian Bulkowski

14

此方法还将允许使用列出的文件名,例如$?和作为文件列表的用户变量。

在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

此信息全部来自博客其他所有人都发布。

多数人似乎建议不要在路径中使用空格或使用Windows 8.3路径,但是如果必须使用空格,则转义空格和进行替换是可行的。


2
如果您突然有一个带有a的文件名+怎么办?
szmoore

1
您将不得不使用文件名中不常见的字符,比如说$$$$或++++
Mr_Moneybags

4

如果您愿意更多地依赖于shell,那么将提供一个列表,其中可以包含带有空格的名称:

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

3

最初的问题是“重命名不是一种选择”,但是许多评论者指出,重命名几乎是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

[旁注:我尝试使用该建议的答案+ss+,但它使我的Makefile难以阅读和调试。当它给我隐含的规则喜欢时,我放弃了它:%.wav : %.ogg ; oggdec "$<"。]


1
一个类似的解决方案,但带有符号链接:savannah.gnu.org/bugs/ ? 712# comment13
Kirill Bulygin '18年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.