Kann GNU Dateinamen mit Leerzeichen verarbeiten?

79

Ich habe ein Verzeichnis mit mehreren Dateien, von denen einige Leerzeichen in ihren Namen haben:

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

Ich benutze den $(wildcard)Befehl von GNU für dieses Verzeichnis und iteriere dann über das Ergebnis, indem $(foreach)ich alles ausdrucke. Hier ist der Code:

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

Folgendes würde ich erwarten, wenn es ausgedruckt wird:

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

Folgendes würde ich tatsächlich bekommen:

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

Letzteres nützt mir offensichtlich nichts. In der Dokumentation zu $(wildcard)Flat-Out heißt es, dass eine "durch Leerzeichen getrennte Liste von Namen" zurückgegeben wird, die damit verbundenen großen Probleme jedoch nicht vollständig berücksichtigt werden. Auch die Dokumentation für $(foreach).

Kann man das umgehen? Wenn das so ist, wie? Das Umbenennen jeder Datei und jedes Verzeichnisses zum Entfernen der Leerzeichen ist keine Option.

qntm
quelle

Antworten:

58

Der Fehler Nr. 712 legt nahe, dass make keine Namen mit Leerzeichen verarbeitet. Nirgendwo niemals.

Ich habe einen Blog-Beitrag gefunden, der besagt, dass er teilweise implementiert wird, indem die Leerzeichen mit \( \\scheint Tippfehler oder Formatierungsartefakt zu sein) umgangen werden, aber:

  • Es funktioniert in keiner Funktion außer $(wildcard).
  • Es funktioniert nicht , wenn Listen mit Namen von Variablen erweitert, die die speziellen Variablen enthält $?, $^und $+sowie alle benutzerdefinierten Variablen. $(wildcard)Dies bedeutet wiederum, dass Sie zwar mit den richtigen Dateien übereinstimmen, das Ergebnis jedoch ohnehin nicht interpretieren können.

Mit expliziten oder sehr einfachen Musterregeln können Sie es zum Laufen bringen, aber darüber hinaus haben Sie kein Glück. Sie müssen nach einem anderen Build-System suchen, das Leerzeichen unterstützt. Ich bin mir nicht sicher, ob Jam / Bjam , Scons , Waf , Ant , Nant und Msbuild funktionieren.

Jan Hudec
quelle
Ich konnte bekommen $?und $@. Wenn Sie interessiert sind, sehen Sie meine Antwort unten. und Louis, ist falsch, es funktioniert. Fühlen Sie sich frei, es selbst zu testen
Mr_Moneybags
21

GNU Make funktioniert sehr schlecht mit durch Leerzeichen getrennten Dateinamen.

Leerzeichen werden überall als Trennzeichen in der Wortliste verwendet.

Dieser Blog-Beitrag fasst die Situation gut zusammen, aber WARNUNG: Er verwendet fälschlicherweise \\ anstelle von \

target: some\ file some\ other\ file

some\ file some\ other\ file:
    echo done

Sie können auch Variablen verwenden, damit dies auch funktioniert

VAR := some\ file some\ other\ file

target: $(VAR)

$(VAR):
    echo done

Nur die wildcardFunktion erkennt das Entkommen, sodass Sie ohne große Schmerzen nichts Besonderes tun können.


Vergessen Sie jedoch nicht, dass Ihre Shell auch Leerzeichen als Trennzeichen verwendet .

Wenn ich das ändern wollte , echo doneum touch $@, würde ich slash hinzufügen , um es für meine Shell zu entkommen.

VAR := some\ file

target: $(VAR)

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

oder verwenden Sie eher Anführungszeichen

VAR := some\ file some\ other\ file

target: $(VAR)

$(VAR):
    touch '$@'

Wenn Sie am Ende viel Schmerz vermeiden möchten, sowohl in GNU make als auch in Ihrer Shell, setzen Sie keine Leerzeichen in Ihre Dateinamen. Wenn Sie dies tun, werden hoffentlich die begrenzten Funktionen von Make ausreichen.

Paul Draper
quelle
4
"Fügen Sie keine Leerzeichen in Ihre Dateinamen ein": Das tue ich nie. Aber manchmal muss man eine make-Datei schreiben, die mit dem Quellcode eines anderen funktioniert ...
Mars
@ Mars, ich verstehe. Sei einfach auf den Schmerz vorbereitet.
Paul Draper
Kein Scherz, Paul. Ich glaube, ich habe ein paar Stunden damit verbracht, verschiedene Dinge auszuprobieren. Ich habe versucht, anhand der Existenz einer Datei eine Version zu testen. Ich gab auf. Jeder muss jetzt die gleiche Version verwenden. (Was in meinem Fall nicht so schwer ist, aber es ist eine unelegante Lösung.)
Mars
Zum Glück können Sie immer noch $(shell ...)erste Manipulationen durchführen.
o11c
1
Ich benutze WSL, also habe ich alle Linux-Tools unter Windows ... und alle meine Binärdateien befinden sich in "Programme". Daaaang.
Brian Bulkowski
14

Diese Methode ermöglicht auch die Verwendung von aufgelisteten Dateinamen wie $?und Benutzervariablen, die Listen von Dateien sind.

Der beste Weg, mit Leerzeichen in Make umzugehen, besteht darin, andere Zeichen durch Leerzeichen zu ersetzen.

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,$@)

Ausgänge

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

Sie können dann Listen mit Dateinamen mit allen GNU Make-Funktionen sicher bearbeiten. Entfernen Sie unbedingt die +, bevor Sie diese Namen in einer Regel verwenden.

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:

Ausgänge

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

Diese Informationen stammen alle aus dem Blog , den alle anderen gepostet haben.

Die meisten Leute scheinen zu empfehlen, keine Leerzeichen in Pfaden oder Windows 8.3-Pfade zu verwenden. Wenn Sie jedoch Leerzeichen verwenden müssen, funktioniert das Escape-Leerzeichen und das Ersetzen.

Mr_Moneybags
quelle
2
Was ist, wenn Sie plötzlich einen Dateinamen mit einem +darin haben?
Szmoore
1
Sie müssten ungewöhnliche Zeichen verwenden, um Dateinamen zu verwenden, z. B. $$$$ oder ++++
Mr_Moneybags
4

Wenn Sie bereit sind, sich ein bisschen mehr auf Ihre Shell zu verlassen, erhalten Sie eine Liste, die Namen mit Leerzeichen enthalten kann:

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

Die ursprüngliche Frage besagte, dass "Umbenennen keine Option ist", doch viele Kommentatoren haben darauf hingewiesen, dass das Umbenennen so ziemlich die einzige Möglichkeit ist, wie Make mit Leerzeichen umgehen kann. Ich schlage einen Mittelweg vor: Verwenden Sie Make, um die Dateien vorübergehend umzubenennen und sie dann wieder umzubenennen. Dies gibt Ihnen die ganze Macht von Make mit impliziten Regeln und anderen Vorteilen, bringt aber Ihr Dateinamenschema nicht durcheinander.

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

Sie können diese Ziele von Hand mit make nospacesund aufrufen make yesspaces, oder Sie können andere Ziele haben, die von ihnen abhängen. Beispielsweise möchten Sie möglicherweise ein "Push" -Ziel haben, das sicherstellt, dass die Leerzeichen wieder in Dateinamen eingefügt werden, bevor Dateien wieder mit einem Server synchronisiert werden:

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

[Nebenbei bemerkt: Ich habe versucht , die Antwort , die unter Verwendung vorgeschlagen +sund s+aber es machte meine Make härter und debuggen zu lesen. Ich habe es aufgegeben, als es mich über implizite Regeln beschimpfte, wie : %.wav : %.ogg ; oggdec "$<".]

hackerb9
quelle
1
Eine ähnliche Lösung, jedoch mit Symlinks: savannah.gnu.org/bugs/?712#comment13 .
Kirill Bulygin