2012-03-23 17 views
48

Tôi có một thư mục chứa nhiều file, một số trong đó có khoảng trống trong tên của họ:GNU có thể xử lý tên tập tin bằng dấu cách không?

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

tôi sử dụng lệnh GNU của $(wildcard) vào thư mục này, và sau đó lặp qua các kết quả sử dụng $(foreach), in ra tất cả mọi thứ. Dưới đây là các mã:

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

Dưới đây là những gì tôi mong chờ để thấy in ra:

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

Đây là những gì tôi thực sự sẽ nhận được:

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

Sau đó rõ ràng là không sử dụng đến tôi. documentation dành cho $(wildcard) nói rõ rằng nó trả về "danh sách các tên được phân tách bằng dấu cách" nhưng hoàn toàn không nhận ra những vấn đề lớn mà điều này đặt ra. Cũng không phải documentation cho $(foreach).

Có thể giải quyết vấn đề này không? Nếu vậy, làm thế nào? Đổi tên mọi tệp và thư mục để xóa không gian không phải là một tùy chọn.

Trả lời

35

Lỗi #712 gợi ý rằng việc thực hiện không xử lý tên có dấu cách. Không đâu, không bao giờ.

Tôi tìm thấy một blog post saying it's partially implemented bằng cách thoát khỏi không gian với \ (\\ dường như được typo hoặc định dạng artefact), nhưng:

  • Nó không làm việc trong bất kỳ chức năng trừ $(wildcard).
  • Nó không hoạt động khi mở rộng danh sách tên từ biến, bao gồm các biến đặc biệt $?, $^$+ cũng như bất kỳ biến do người dùng xác định. Điều này có nghĩa là trong khi $(wildcard) sẽ khớp với các tệp chính xác, bạn sẽ không thể diễn giải kết quả.

Vì vậy, với quy tắc mẫu rõ ràng hoặc rất đơn giản, bạn có thể làm cho nó hoạt động, nhưng ngoài ra bạn sẽ không may mắn. Bạn sẽ phải tìm một số hệ thống xây dựng khác hỗ trợ không gian. Tôi không chắc chắn liệu jam/bjam có, scons, waf, ant, nantmsbuild tất cả đều hoạt động.

+0

Tôi có thể nhận được '$?' Và '$ @'. Nếu bạn quan tâm, hãy xem câu trả lời của tôi bên dưới. và Louis, sai, nó hoạt động. Cảm thấy tự do để thử nghiệm nó ra cho mình –

11

GNU Thực hiện rất kém với tên tệp được phân tách bằng dấu cách.

Dấu cách được sử dụng làm dấu phân cách trong danh sách từ khắp nơi.

This blog post tóm tắt tình hình tốt, nhưng Chú ý: nó không đúng cách sử dụng \\ chứ không phải là \

target: some\ file some\ other\ file 

some\ file some\ other\ file: 
    echo done 

Bạn cũng có thể sử dụng các biến, vì vậy đây cũng sẽ làm việc

VAR := some\ file some\ other\ file 

target: $(VAR) 

$(VAR): 
    echo done 

Chỉ chức năng wildcard mới nhận diện được lối thoát, vì vậy bạn không thể làm bất cứ điều gì ưa thích mà không có nhiều đau đớn.


Nhưng đừng quên rằng vỏ của bạn sử dụng không gian như delimiters quá.

Nếu tôi muốn thay đổi echo done thành touch [email protected], tôi phải thêm dấu gạch chéo để thoát khỏi vỏ của tôi.

VAR := some\ file 

target: $(VAR) 

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

hay, nhiều khả năng, sử dụng trích dẫn

VAR := some\ file some\ other\ file 

target: $(VAR) 

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

Cuối cùng, nếu bạn muốn tránh được rất nhiều đau đớn, cả về GNU thực hiện, và trong shell của bạn, don' t đặt không gian trong tên tập tin của bạn. Nếu bạn làm vậy, hy vọng rằng khả năng giới hạn của Make sẽ là đủ.

+1

"không đặt không gian trong tên tập tin của bạn": Tôi không bao giờ làm. Nhưng đôi khi bạn phải viết một tệp làm việc với mã nguồn của người khác .... – Mars

+0

@Mars, tôi hiểu. Chỉ cần chuẩn bị cho cơn đau. –

+0

Không đùa đâu, Paul. Tôi nghĩ rằng tôi đã dành một vài giờ thử những thứ khác nhau. Tôi đã cố gắng để thử nghiệm cho một phiên bản bằng sự tồn tại của một tập tin. Tôi từ bỏ. Mọi người đều phải sử dụng cùng một phiên bản ngay bây giờ. (Đó không phải là khó khăn trong trường hợp của tôi, nhưng đó là một giải pháp không thích hợp.) – Mars

10

Phương pháp này cũng sẽ cho phép sử dụng tên tệp được liệt kê chẳng hạn như $? và biến người dùng là danh sách tệp.

Cách tốt nhất để giải quyết các khoảng trống trong Make là thay thế khoảng trống cho các ký tự khác.

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

Đầu ra

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

Sau đó bạn có thể thao tác danh sách các tên tập tin sử dụng tất cả các GNU Make chức năng một cách an toàn. Chỉ cần chắc chắn để loại bỏ các + trước khi sử dụng các tên này trong một quy tắc.

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: 

Đầu ra

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

Thông tin này là tất cả từ blog rằng mọi người khác đã được đăng.

Hầu hết mọi người dường như đang đề xuất không sử dụng dấu cách trong đường dẫn hoặc sử dụng đường dẫn Windows 8.3, nhưng nếu bạn phải sử dụng dấu cách, không gian thoát và công việc thay thế.

3

Nếu bạn sẵn sàng dựa vào shell của bạn nhiều hơn một chút, điều này mang lại một danh sách mà có thể giữ tên với không gian tốt:

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

Các câu hỏi ban đầu nói rằng "đổi tên không phải là một lựa chọn", nhưng nhiều người bình luận đã chỉ ra rằng đổi tên là khá nhiều cách duy nhất Hãy có thể xử lý không gian. Tôi đề nghị một cách trung gian: Sử dụng Make để tạm thời đổi tên các tập tin và sau đó đổi tên chúng trở lại.Điều này mang lại cho bạn tất cả sức mạnh của Thực hiện với các quy tắc ngầm định và lòng tốt khác, nhưng không làm hỏng chương trình đặt tên tệp của bạn.

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

Bạn có thể gọi đó là các mục tiêu bằng tay với make nospacesmake yesspaces, hoặc bạn có thể có các mục tiêu khác phụ thuộc vào họ. Ví dụ, bạn có thể muốn có một "đẩy" mục tiêu mà làm cho chắc chắn để đặt các không gian trở lại trong tên tập tin trước khi đồng bộ các file lại với một máy chủ:

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

[Phụ chú: Tôi đã thử các câu trả lời mà đề nghị sử dụng +ss+ nhưng nó làm cho Makefile của tôi khó đọc và gỡ lỗi hơn. Tôi đã từ bỏ nó khi nó cho tôi guff về các quy tắc ngầm thích: %.wav : %.ogg ; oggdec "$<".]

Các vấn đề liên quan