Может ли GNU создавать имена файлов с пробелами?

У меня есть каталог, содержащий несколько файлов, некоторые из которых имеют пробелы в именах:

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

Я использую команду GNU $(wildcard) в этом каталоге, а затем перебираю результат с помощью $(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) flat-out заявляет, что возвращает "список имен, разделенных пробелами", но полностью не признает огромные проблемы, которые возникают. Также документация для $(foreach).

Можно ли обойти это? Если да, то как? Переименование каждого файла и каталога для удаления пробелов не является вариантом.

Ответ 1

Ошибка # 712 предполагает, что make не обрабатывает имена с пробелами. Нигде, никогда.

Я нашел сообщение jam/bjam делает, scons, waf, ant, nant и msbuild все должно работать.

Ответ 2

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 done на touch [email protected], мне пришлось бы добавить косой чертой, чтобы избежать его для моей оболочки.

VAR := some\ file

target: $(VAR)

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

или, более вероятно, использовать кавычки

VAR := some\ file some\ other\ file

target: $(VAR)

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

В конце концов, если вы хотите избежать большой боли, как в GNU make, так и в своей оболочке, не помещайте пробелы в имена файлов. Если вы это сделаете, мы надеемся, что ограниченные возможности Make будут достаточными.

Ответ 3

Этот метод также позволит использовать перечисленные имена файлов, такие как $? и пользовательские переменные, которые являются списками файлов.

Лучший способ справиться с пробелами в 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,[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])

Выходы

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, но если вы должны использовать пробелы, вы можете использовать пробелы и подстановки.

Ответ 4

Если вы хотите больше полагаться на свою оболочку, это дает список, который может содержать имена с пробелами просто:

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

Ответ 5

В оригинальном вопросе говорилось, что "переименование не является вариантом", но многие комментаторы указали, что переименование в значительной степени является единственным способом, которым 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, иначе у вас могут быть другие цели. Например, вы можете захотеть иметь "push" цель, которая позволяет помещать пробелы в имена файлов, прежде чем синхронизировать файлы с сервером:

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

[Sidenote: Я попробовал ответить, который предложил использовать +s и s+, но это сделало мой Makefile труднее читать и отлаживать. Я отказался от этого, когда он дал мне guff по поводу неявных правил: %.wav : %.ogg ; oggdec "$<".]