2012-03-23 17 views
48

ho una directory contenente diversi file, alcuni dei quali hanno spazi nei loro nomi:GNU può gestire nomi di file con spazi?

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

io uso il comando di GNU $(wildcard) su questa directory, e poi iterare il risultato usando $(foreach), la stampa di tutto. Ecco il codice:

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

Ecco quello che si aspetta di vedere stampato:

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

Ecco cosa vorrei davvero ottenere:

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

Quest'ultimo è ovviamente di alcuna utilità per me. Lo standard documentation per $(wildcard) dichiara che restituisce un "elenco di nomi separato dallo spazio" ma non riesce a riconoscere completamente gli enormi problemi che questo solleva. Né lo documentation per $(foreach).

È possibile aggirare questo problema? Se é cosi, come? Rinominare ogni file e directory per rimuovere gli spazi non è un'opzione.

risposta

35

Il bug #712 suggerisce che make non gestisce nomi con spazi. Da nessuna parte, mai.

Ho trovato un blog post saying it's partially implemented scappando gli spazi con \ (\\ sembra essere errore di battitura o la formattazione manufatto), ma:

  • Non funziona in tutte le funzioni ad eccezione della $(wildcard).
  • Non funziona quando si espandono gli elenchi di nomi da variabili, che include le variabili speciali $?, $^ e $+ nonché qualsiasi variabile definita dall'utente. Il che a sua volta significa che mentre $(wildcard) corrisponderà ai file corretti, non sarà comunque possibile interpretare il risultato.

Quindi con regole del modello esplicite o molto semplici è possibile farlo funzionare, ma oltre a ciò si è sfortunati. Dovrai cercare un altro sistema di build che supporti gli spazi. Non sono sicuro che sia jam/bjam, scons, waf, ant, nant e msbuild che tutti dovrebbero funzionare.

+0

sono stato in grado di ottenere '$' e '$ @'?. Se sei interessato, vedi la mia risposta qui sotto. e Louis, ha torto, funziona. Sentiti libero di provarlo da te –

11

GNU Make funziona molto male con nomi di file separati da spazi.

Gli spazi vengono utilizzati come delimitatori nell'elenco di parole in tutto il luogo.

This blog post riassume bene la situazione, ma ATTENZIONE: utilizza in modo non corretto, piuttosto che \\ \

target: some\ file some\ other\ file 

some\ file some\ other\ file: 
    echo done 

È inoltre possibile utilizzare le variabili, quindi questo sarebbe anche lavorare

VAR := some\ file some\ other\ file 

target: $(VAR) 

$(VAR): 
    echo done 

Solo la funzione wildcard riconosce l'escaping, quindi non puoi fare niente di speciale senza molto dolore.


Ma non dimenticate che la shell utilizza gli spazi come delimitatori troppo.

Se volessi cambiare il echo done a touch [email protected], dovrei aggiungere la barra per fuggire per la mia shell.

VAR := some\ file 

target: $(VAR) 

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

o, più probabilmente, l'uso cita

VAR := some\ file some\ other\ file 

target: $(VAR) 

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

Alla fine, se si vuole evitare un sacco di dolore, sia in GNU make, e nella shell, don' t inserire spazi nei nomi dei file. Se lo fai, speriamo che le capacità limitate di Make saranno sufficienti.

+1

"non inserire spazi nei tuoi nomi di file": non lo faccio mai. Ma a volte devi scrivere un file make che funzioni con il codice sorgente di qualcun altro .... – Mars

+0

@Mars, ho capito. Preparati solo per il dolore. –

+0

No scherzo, Paul. Penso di aver passato un paio d'ore a provare cose diverse. Stavo cercando di testare una versione dall'esistenza di un file. Ho mollato. Tutti devono usare la stessa versione ora. (Che non è poi così difficile nel mio caso, ma è una soluzione poco elegante.) – Mars

10

Questo metodo consente inoltre l'uso di nomi di file elencati come $? e variabili utente che sono elenchi di file.

Il modo migliore per gestire gli spazi in Crea è sostituire gli spazi con altri caratteri.

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]) 

uscite

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

È quindi possibile manipolare in modo sicuro elenchi di nomi di file utilizzando tutto il GNU Make funzioni. Assicurati di rimuovere i + prima di usare questi nomi in una regola.

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: 

uscite

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

Questa informazione è tutto dalla blog che tutti gli altri è stato distacco.

La maggior parte delle persone sembra raccomandare di non utilizzare spazi nei percorsi o utilizzare i percorsi di Windows 8.3, ma se è necessario utilizzare gli spazi, gli spazi di escape e le operazioni di sostituzione.

3

Se siete disposti a fare affidamento sul vostro guscio un po 'di più, questo dà un elenco che può contenere i nomi con gli spazi più che bene:

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

La domanda originale ha detto che "la ridenominazione non è un'opzione", tuttavia molti commentatori hanno sottolineato che la ridenominazione è praticamente l'unico modo in cui Make può gestire gli spazi. Suggerisco una via di mezzo: usa Make per rinominare temporaneamente i file e rinominarli di nuovo.Questo ti dà tutta la potenza di Make con regole implicite e altre qualità, ma non rovina il tuo schema di denominazione dei file.

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

Si può chiamare questi obiettivi a mano con make nospaces e make yesspaces, o si può avere altri obiettivi dipende da loro. Ad esempio, si potrebbe desiderare di avere un obiettivo "push", che fa in modo di mettere gli spazi di nuovo nei nomi dei file prima della sincronizzazione di file indietro con un server:

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

[Sidenote: ho provato la risposta che ha suggerito di utilizzare +s e s+ ma ha reso il mio Makefile più difficile da leggere ed eseguire il debug. Ho rinunciato su di esso quando mi ha dato guff sulle regole implicite piace:. %.wav : %.ogg ; oggdec "$<"]

Problemi correlati