2012-03-23 13 views
48

Tengo un directorio que contiene varios archivos, algunos de los cuales tienen espacios en sus nombres:¿Puede GNU hacer manejar nombres de archivos con espacios?

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

Yo uso de comandos de GNU $(wildcard) en este directorio, y luego iterar sobre el resultado utilizando $(foreach), la impresión de todo. Aquí está el código:

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

Esto es lo que se esperaría ver impreso:

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

aquí es lo que haría realidad sale:

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

Este último es, obviamente, de ninguna utilidad para yo. El documentation para $(wildcard) establece que devuelve una "lista de nombres separados por espacios", pero no reconoce los enormes problemas que esto plantea. Tampoco lo hace el documentation para $(foreach).

¿Es posible evitar esto? ¿Si es así, cómo? Cambiar el nombre de cada archivo y directorio para eliminar los espacios no es una opción.

Respuesta

35

El error #712 sugiere que make no maneje nombres con espacios. En ninguna parte, nunca.

encontré una blog post saying it's partially implemented por escapar de los espacios con \ (\\ parece estar error tipográfico o artefacto formato), pero:

  • No funciona en cualquier función, excepto $(wildcard).
  • No funciona al expandir listas de nombres de variables, que incluye las variables especiales $?, $^ y $+, así como cualquier variable definida por el usuario. Lo que a su vez significa que aunque $(wildcard) coincidirá con los archivos correctos, no podrá interpretar el resultado de todos modos.

Así que con reglas de patrón explícitas o muy simples puede hacer que funcione, pero más allá de eso no tiene suerte. Tendrás que buscar algún otro sistema de compilación que soporte espacios. No estoy seguro de si jam/bjam, scons, waf, ant, nant y msbuild todos deberían funcionar.

+0

Pude obtener '$?' Y '$ @'. Si está interesado, vea mi respuesta a continuación. y Louis, está equivocado, funciona. No dude en probarlo usted mismo –

11

GNU Make hace muy mal con nombres de archivo separados por espacios.

Los espacios se utilizan como delimitadores en la lista de palabras de todo el lugar.

This blog post resume la situación así, pero ADVERTENCIA: se utiliza incorrectamente en lugar de \\ \

target: some\ file some\ other\ file 

some\ file some\ other\ file: 
    echo done 

También puede utilizar variables, por lo que también podría funcionar

VAR := some\ file some\ other\ file 

target: $(VAR) 

$(VAR): 
    echo done 

Solo la función wildcard reconoce el escape, por lo que no puede hacer nada sofisticado sin mucho dolor.


Pero no hay que olvidar que el shell utiliza espacios como delimitadores demasiado.

Si quisiera cambiar el echo done al , tendría que agregar una barra para escapar de mi caparazón.

VAR := some\ file 

target: $(VAR) 

$(VAR): 
    touch $(subst \,\\,[email protected]) 

o, más probablemente, el uso cita

VAR := some\ file some\ other\ file 

target: $(VAR) 

$(VAR): 
    touch '[email protected]' 

Al final, si se quiere evitar una gran cantidad de dolor, tanto en GNU make, y en su concha, don' Pon espacios en tus nombres de archivo. Si lo hace, es de esperar que las capacidades limitadas de Make sean suficientes.

+1

"no ponga espacios en sus nombres de archivo": nunca lo hago. Pero a veces tienes que escribir un archivo make que funcione con el código fuente de otra persona ... – Mars

+0

@Mars, lo entiendo. Solo prepárate para el dolor. –

+0

No es broma, Paul. Creo que pasé un par de horas intentando cosas diferentes. Estaba intentando probar una versión por la existencia de un archivo. Me di por vencido. Todos tienen que usar la misma versión ahora. (Lo cual no es tan difícil en mi caso, pero es una solución poco elegante.) – Mars

10

Este método también permitirá el uso de los nombres de archivos que aparecen como $? y variables de usuario que son listas de archivos.

La mejor manera de hacer frente a los espacios en hacer es sustituir los espacios para otros caracteres.

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,[email protected]) from $(call +s,$?) 

$(call s+,bar\ baz): 

    @echo Making $(call +s,[email protected]) 

$(call s+,bar\ baz2): 

    @echo Making $(call +s,[email protected]) 

salidas

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

A continuación, puede manipular con seguridad las listas de nombres de archivo con toda la GNU Make funciones. Solo asegúrese de eliminar los + 's antes de usar estos nombres en una regla.

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: 

salidas

in rule: a b.o 
Object files: a b.o c d.o e f.o 

Esta información es todo desde la blog que todos los demás estaban publicando.

La mayoría de la gente parece estar recomendando el uso de espacios en las rutas o el uso de rutas de Windows 8.3, pero si tiene que usar espacios, espacios que escapan y obras de sustitución.

3

Si usted está dispuesto a confiar en su concha un poco más, esto da una lista que puede contener nombres con espacios muy bien:

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

La pregunta original dijo que "el cambio de nombre no es una opción", sin embargo, muchos comentaristas han señalado que el cambio de nombre es prácticamente la única forma en que Make puede manejar espacios. Sugiero una manera intermedia: use Make para cambiar el nombre de los archivos temporalmente y luego cámbieles el nombre.Esto le da todo el poder de Make con reglas implícitas y otras bondades, pero no estropea su esquema de nombres de archivo.

# 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* 

Usted podría llamar a estos objetivos a mano con make nospaces y make yesspaces, o puede tener otros objetivos depende de ellos. Por ejemplo, es posible que desee tener un objetivo "push", que se asegura de poner los espacios de vuelta en los nombres de archivo antes de sincronizar los archivos de nuevo con un servidor:

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

[Nota al margen: Me trató la respuesta que sugirió el uso de +s y s+ pero hizo que mi Makefile fuera más difícil de leer y depurar. Me di por vencido cuando me dio guff sobre reglas implícitas me gusta: %.wav : %.ogg ; oggdec "$<".]

Cuestiones relacionadas