2009-05-11 34 views
8

Khi sử dụng một vỏ POSIX, sauTricky mở rộng cú đúp trong vỏ

touch {quick,man,strong}ly 

mở rộng để

touch quickly manly strongly 

Mà sẽ chạm vào file quickly, manly, và strongly, nhưng là nó có thể tự động tạo mở rộng? Ví dụ: phần sau minh họa những gì tôi muốn làm nhưng không hoạt động vì thứ tự mở rộng:

TEST=quick,man,strong #possibly output from a program 
echo {$TEST}ly 

Có cách nào để đạt được điều này không? Tôi không ngại ràng buộc bản thân mình với Bash nếu cần thiết. Tôi cũng muốn tránh các vòng lặp. Việc mở rộng nên được đưa ra như là các đối số hoàn chỉnh cho bất kỳ chương trình tùy ý nào (tức là chương trình không thể được gọi một lần cho mỗi tệp, nó chỉ có thể được gọi một lần cho tất cả các tệp). Tôi biết về xargs nhưng tôi hy vọng nó có thể được thực hiện từ vỏ bằng cách nào đó.

+0

mở rộng Brace không được định nghĩa trong vỏ POSIX: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06 – pabouk

+2

@pabouk: Đúng vậy, bây giờ tôi biết mở rộng cú đúp không phải là POSIX, nhưng 7 năm trước (khi tôi hỏi câu hỏi này) Tôi không biết điều đó :) – dreamlax

Trả lời

17

... Có quá nhiều sai với việc sử dụng eval. Những gì bạn đang yêu cầu chỉ có thể thực hiện với eval, NHƯNG những gì bạn có thể muốn có thể dễ dàng thực hiện mà không cần phải sử dụng bash bug-central.

Sử dụng mảng! Bất cứ khi nào bạn cần giữ nhiều mục trong một kiểu dữ liệu, bạn cần (hoặc, nên sử dụng) một mảng.

TEST=(quick man strong) 
touch "${TEST[@]/%/ly}" 

Điều đó thực hiện chính xác những gì bạn muốn mà không có hàng nghìn lỗi và vấn đề bảo mật được giới thiệu và ẩn trong các đề xuất khác tại đây.

Cách nó hoạt động là:

  • "${foo[@]}": Mở rộng mảng tên foo bằng cách mở rộng mỗi phần tử của nó, trích dẫn đúng cách. Đừng quên các dấu ngoặc kép!
  • ${foo/a/b}: Đây là loại mở rộng thông số thay thế cho số a đầu tiên trong số's mở rộng thêm b. Trong loại mở rộng này, bạn có thể sử dụng % để biểu thị kết thúc của giá trị được mở rộng, tương tự như $ trong cụm từ thông dụng.
  • Đặt tất cả những thứ đó lại với nhau và "$ {foo [@] /%/ly}" sẽ mở rộng từng phần tử foo, trích dẫn chính xác như một đối số riêng biệt và thay thế kết thúc của từng phần tử theo ly.
+0

Bất kỳ đề xuất cho điều đó cho nhiều cấp độ mở rộng? ví dụ, 'echo {a, b}/{c, d}/{e, f}' cho 'a/c/ea/c/fa/d/ea/d/fb/c/eb/c/fb/d/eb/d/f'; Tôi có thể đạt được điều đó với mảng, mà không cần phải viết vòng? – sdaau

+0

@sdaau Bạn có thể gán dấu ngoặc mở rộng cho một mảng. tệp = ({a, b}/{c, d}/{e, f}); chạm vào "$ {files [@]}" – lhunath

+0

Lưu ý rằng bạn có thể sử dụng '#' thay vì '%' cho các mục tiền tố: '$ {TEST [@]/#/ly}' cho 'lyquick lyman lystrong' – Jezz

3

Trong bash, bạn có thể làm điều này:

#!/bin/bash 
TEST=quick,man,strong 
eval echo $(echo {$TEST}ly) 
#eval touch $(echo {$TEST}ly) 

Đó dòng cuối cùng là nhận xét ra nhưng sẽ chạm vào các tập tin cụ thể.

+3

Để bạn biết, có rất nhiều vấn đề với giải pháp đó, điều này chỉ ẩn vì bạn chỉ sử dụng các chữ cái và dấu phẩy trong tham số TEST của mình. Bất kỳ nhân vật nào có ý nghĩa đặc biệt trong bash sẽ làm hỏng nó, đặc biệt là vì bạn thậm chí hoàn toàn thất bại trong việc trích dẫn bất cứ điều gì. Tôi nhận ra đó là một bản demo với các dữ liệu đã cho nhưng việc sử dụng giải pháp này trong các ứng dụng thế giới thực là một tội lỗi. – lhunath

+0

@paxdiablo: Bạn có thể sử dụng 'eval echo {$ TEST} ly' thay vì' eval echo $ (echo {$ TEST} ly) '. AFAIK tiếng vọng thêm không thêm bất cứ thứ gì. – iconoclast

+0

@ lhunath: bạn dường như coi thường 'eval'. Có cái gì đó đặc biệt sai với điều này mà sẽ gây ra một vấn đề, hoặc bạn chỉ đơn giản là xem xét bất cứ điều gì với 'eval' được tự động cái ác? – iconoclast

0

Lấy cảm hứng từ những câu trả lời ở trên:

$ TEST=quick,man,strong 
$ touch $(eval echo {$TEST}ly) 
0

Zsh có thể dễ dàng làm điều đó:

TEST=quick,man,strong 
print ${(s:,:)^TEST}ly 

nội dung Variable được tách ra ở dấu phẩy, sau đó mỗi phần tử được phân phối cho các chuỗi xung quanh niềng răng:

quickly manly strongly 
Các vấn đề liên quan