Может ли GNU обрабатывать имена файлов с пробелами? - PullRequest
66 голосов
/ 23 марта 2012

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

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

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

Ответы [ 5 ]

49 голосов
/ 23 марта 2012

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

Я нашел сообщение в блоге , в котором говорится, что оно частично реализовано за счет исключения пробелов с помощью \ (\\ кажется опечаткой или артефактом форматирования), но:

  • Он не работает ни в одной функции, кроме $(wildcard).
  • Он не работает при расширении списков имен из переменных, который включает специальные переменные $?, $^ и$+ а также любая пользовательская переменная.Это, в свою очередь, означает, что хотя $(wildcard) будет соответствовать правильным файлам, вы все равно не сможете интерпретировать результат.

Так что с помощью явных или очень простых правил шаблонов вы можете заставить его работать,но кроме этого вам не повезло.Вам придется искать какую-то другую систему сборки, которая поддерживает пробелы.Я не уверен, что jam / bjam , scons , waf , ant , nant и msbuild все должно работать.

18 голосов
/ 25 мая 2014

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 $@, мне пришлось бы добавить косую черту, чтобы скрыть его для моей оболочки.

VAR := some\ file

target: $(VAR)

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

или, большескорее всего, используйте кавычки

VAR := some\ file some\ other\ file

target: $(VAR)

$(VAR):
    touch '$@'

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

12 голосов
/ 01 февраля 2015

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

Лучший способ справиться с пробелами в 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,$@) from $(call +s,$?)

$(call s+,bar\ baz):

    @echo Making $(call +s,$@)

$(call s+,bar\ baz2):

    @echo Making $(call +s,$@)

Выходы

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 голосов
/ 22 декабря 2016

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

$(shell find | sed 's: :\\ :g')
1 голос
/ 06 августа 2017

В первоначальном вопросе говорилось, что «переименование - это не вариант», однако многие комментаторы отмечают, что переименование является практически единственным способом, которым 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.Я отказался от этого, когда это дало мне повод для неявных правил лайков: %.wav : %.ogg ; oggdec "$<".]

...