Можно так обрабатывать имена файлов с пробелами?

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

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

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

6 ответов


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

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

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

таким образом, с явными или очень простыми правилами шаблонов вы можете заставить его работать, но помимо этого вам не повезло. Вам придется искать другую систему сборки, которая поддерживает пространства. Я не уверен, что варенье/bjam нет, проектов SCons, waf, АНТ, nant и в MSBuild все должно работать.


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

VAR := some\ file

target: $(VAR)

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

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

VAR := some\ file some\ other\ file

target: $(VAR)

$(VAR):
    touch '$@'

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


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

лучший способ справиться с пробелами в Make-заменить пробелы другими символами.

s+ = $(subst \ ,+,)

+s = $(subst +,\ ,)

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


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

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

исходный вопрос сказал, что" переименование не является вариантом", но многие комментаторы указали, что переименование-это в значительной степени единственный способ сделать может обрабатывать пробелы. Я предлагаю средний способ: Используйте 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 "$<".]


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

$ 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 <==
$