Чи може GNU зробити обробник імен файлів із пробілами?


80

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

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

Я використовую $(wildcard)команду GNU для цього каталогу, а потім переглядаю результат, використовуючи $(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).

Чи можна обійти це? Якщо так, то як? Перейменування кожного файлу та каталогу для видалення пробілів не є можливим.

Відповіді:


59

Помилка # 712 припускає, що make не обробляє імена з пробілами. Ніде, ніколи.

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

  • Це не працює в жодних функціях, крім $(wildcard).
  • Вона не працює при розширенні списку імен з змінних, яка включає в себе спеціальні змінні $?, $^а $+так само як будь-який призначену для користувача змінну. Що, в свою чергу, означає, що, хоча вони $(wildcard)будуть відповідати правильним файлам, ви все одно не зможете інтерпретувати результат.

Тож за допомогою явних або дуже простих правил шаблону ви можете змусити його працювати, але крім цього вам не пощастило. Вам доведеться шукати якусь іншу систему складання, яка підтримує простори. Я не впевнений , є чи джем / bjam робить, SCons , WAF , мураха , Нан і MSBuild все повинно працювати.


Я зміг отримати $?і $@. Якщо вам цікаво, дивіться мою відповідь нижче. і Луї, помиляється, це працює. Не соромтеся випробувати це самі
Mr_Moneybags

21

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 буде достатньо.


4
"не вставляйте пробіли у ваші імена файлів": я ніколи не роблю. Але іноді доводиться писати файл make, який працює з чужим вихідним кодом ....
Марс,

@ Марс, я розумію. Просто будьте готові до болю.
Пол Дрейпер

Не жартуй, Пол. Думаю, пару годин пробував різні речі. Я намагався перевірити наявність версії на наявність файлу. Я здався. Зараз всі мають використовувати одну і ту ж версію. (Що не так складно в моєму випадку, але це неелегантне рішення.)
Марс,

Ви все ще можете використовувати $(shell ...)для початкових маніпуляцій, на щастя.
o11c

2
Я використовую WSL, тому у мене є всі інструменти Linux у Windows .... і всі мої двійкові файли знаходяться в "Програмних файлах". Даааанг.
Брайан Булковскі,

14

Цей метод також дозволить використовувати перелічені імена файлів, такі як $?і користувацькі змінні, які є списками файлів.

Найкращий спосіб мати справу з пробілами в 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, але якщо вам потрібно використовувати пробіли, пробіли та заміна працюють.


2
Що робити, якщо у вас раптом з’явилося ім’я файлу, в якому є +?
szmoore

1
Вам доведеться використовувати символи, незвичні для імен файлів, можливо, скажіть $$$$ або ++++
Mr_Moneybags

4

Якщо ви бажаєте ще трохи покластися на свою оболонку, це дасть список, в якому можуть бути просто імена з пробілами:

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

3

В оригінальному запитанні говорилося, що "перейменування не є варіантом", проте багато коментаторів зазначали, що перейменування - це майже єдиний спосіб, яким 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 "$<"]


1
Подібне рішення, але із символічними посиланнями: savannah.gnu.org/bugs/?712#comment13 .
Кирило Булигін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.