Czy GNU może obsługiwać nazwy plików ze spacjami?

Mam katalog zawierający kilka plików, z których niektóre mają spacje w nazwach:

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

Używam polecenia GNU $(wildcard) w tym katalogu, a następnie iteruję wynik używając $(foreach), wypisując wszystko. Oto kod:

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

Oto, czego bym się spodziewał:

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

Oto, co właściwie dostanę:

Test
workspace
Another
directory
file1.ext
file2.ext
demo
2012-03-23.odp
To ostatnie jest dla mnie oczywiście bezużyteczne. dokumentacja dla $(wildcard) płasko-out stwierdza, że zwraca "rozdzielona spacją Lista nazwisk", ale całkowicie nie uznaje ogromnych problemów, które to stwarza. Nie ma też dokumentacji dla $(foreach).

Czy można to obejść? Jeśli tak, to w jaki sposób? Zmiana nazwy każdego pliku i katalogu w celu usunięcia spacji nie jest opcją.

Author: qntm, 2012-03-23

6 answers

The bug #712 sugeruje, że make nie obsługuje nazw ze spacjami. Nigdzie, nigdy.

Znalazłem wpis na blogu mówiący, że jest częściowo zaimplementowany {[9] } przez ucieczkę spacji z \ (\\ wygląda na literówkę lub artefakt formatowania), ale:

  • nie działa w żadnych funkcjach poza $(wildcard).
  • nie działa przy rozwijaniu list nazw ze zmiennych, które zawierają specjalne zmienne $?, $^ i $+, jak również wszelkie zdefiniowane przez użytkownika zmienna. Co z kolei oznacza, że podczas gdy $(wildcard) dopasuje poprawne pliki, nie będziesz w stanie zinterpretować wyniku.

Więc z wyraźnymi lub bardzo prostymi regułami wzoru możesz to uruchomić, ale poza tym masz pecha. Musisz poszukać innego systemu budowania, który obsługuje spacje. Nie jestem pewien czy dżem/bjam robi, scons, waf, mrówka, nant i msbuild wszystkie powinny działać.

 43
Author: Jan Hudec,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-24 17:34:38

GNU Make bardzo słabo radzi sobie z oddzielonymi spacjami nazwami plików.

Spacje są używane jako ograniczniki w liście słów w całym miejscu.

Ten wpis na blogu dobrze podsumowuje sytuację, ale Ostrzeżenie: niewłaściwie używa \ \ zamiast \

target: some\ file some\ other\ file

some\ file some\ other\ file:
    echo done

Możesz również używać zmiennych, więc to również zadziała

VAR := some\ file some\ other\ file

target: $(VAR)

$(VAR):
    echo done

TYLKO funkcja wildcard rozpoznaje ucieczkę, więc nie możesz zrobić nic fantazyjnego bez dużego bólu.


Ale nie zapominaj, że Twoja powłoka używa spacji jako ograniczników.

Gdybym chciał zmienić echo done na touch $@, musiałbym dodać slash, aby uciec przed nim dla mojej powłoki.

VAR := some\ file

target: $(VAR)

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

Lub, bardziej prawdopodobne, użyj cudzysłowów

VAR := some\ file some\ other\ file

target: $(VAR)

$(VAR):
    touch '$@'

Na koniec, jeĹ "li chcesz uniknÄ ... Ä ‡ duĺźego bĂłlu, zarĂłwno w GNU make, jak i w swojej powĺ' Oce, nie umieszczaj spacji w nazwach plikĂłw. Jeśli to zrobisz, mam nadzieję, że ograniczone możliwości Make będą wystarczające.

 15
Author: Paul Draper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-24 21:35:43

Ta metoda pozwoli również na użycie wymienionych nazw plików, takich jak $? i zmiennych użytkownika, które są listami plików.

Najlepszym sposobem radzenia sobie ze spacjami w Make jest zastąpienie spacji innymi znakami.

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

Wyjścia

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

Możesz wtedy bezpiecznie manipulować listami nazw plików używając całego GNU Make funkcje. Pamiętaj tylko, aby usunąć +przed użyciem tych nazw w regułach.

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:

Wyjścia

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

Ta informacja pochodzi z blog że wszyscy inni publikowali.

Większość ludzi wydaje się zalecać używanie żadnych spacji w ścieżkach lub używanie ścieżek Windows 8.3, ale jeśli musisz używać spacji, odstępujące spacje i zastępowanie działają.

 10
Author: Mr_Moneybags,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-05 22:07:01

Jeśli chcesz bardziej polegać na swojej powłoce, daje to listę, która może pomieścić nazwy ze spacjami:

$(shell find | sed 's: :\\ :g')
 4
Author: benzaita,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-17 00:38:39

Pierwotne pytanie mówiło, że "zmiana nazwy nie jest opcją" , jednak wielu komentatorów zwróciło uwagę, że zmiana nazwy jest właściwie jedynym sposobem, aby obsłużyć spacje. Proponuję środkowy sposób: użyj Make, aby tymczasowo zmienić nazwy plików, a następnie zmienić je z powrotem. Daje to całą moc Make z domyślnymi regułami i innymi dobrociami, ale nie psuje schematu nazewnictwa plików.

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

Możesz nazwać te cele ręcznie make nospaces i make yesspaces, lub możesz mieć inne cele zależy od nich. Na przykład, możesz chcieć mieć cel "push", który upewnia się, że spacje są umieszczane z powrotem w nazwach plików przed synchronizacją plików z serwerem:

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

[Sidenote: próbowałem odpowiedzi, która sugerowała użycie +s i s+, ale sprawiła, że mój plik Makefile był trudniejszy do odczytania i debugowania. Zrezygnowałem z tego, kiedy to dało mi guff nad niejawnymi zasadami lubi: %.wav : %.ogg ; oggdec "$<".]

 1
Author: hackerb9,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-06 12:05:01

Inne odpowiedzi już dość dobrze obejmują problem. Zrobiłem tylko przykład, aby pokazać, że \-escaping działa również dla zależności.

$ 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 <==
$
 0
Author: Kirill Bulygin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-13 15:40:18