Tôi có thể sử dụng các biến trong mở rộng {} mà không có `eval` không?


7

Tôi có thể sử dụng các biến trong {}mở rộng mà không thu hút evalkhông? Nếu vậy thì thế nào?

Điều này không hoạt động:

$ touch 1.foo 1.bar
$ ls 1.{foo,bar}
1.bar  1.foo
$ extensions=foo,bar
$ ls 1.{$extensions}
ls: cannot access 1.{foo,bar}: No such file or directory

Nó hoạt động với eval:

$ eval ls 1.{$extensions}
1.bar  1.foo

3
mở rộng biến xảy ra sau khi mở rộng từ, vì vậy {$ ...} sẽ là một từ đơn. 'tho {$ foo, $ bar} sẽ hoạt động.
Ricky Beam

Câu trả lời:


9

Mở rộng cú đúp xảy ra rất sớm trong quá trình mở rộng (điều đầu tiên, trên thực tế), trước khi mở rộng biến. Để thực hiện mở rộng cú đúp trên kết quả của việc mở rộng biến, bạn cần sử dụng eval.

Bạn có thể đạt được hiệu ứng tương tự mà không cần evalnếu bạn tạo extensionsmột mẫu ký tự đại diện thay vì một mẫu nẹp. Đặt extglobtùy chọn để kích hoạt các mẫu giống như ksh .

shopt -s extglob
extensions='@(foo|bar)'
ls 1.$extensions

3

Đây là một cách để mở rộng các biến trong niềng răng mà không cần eval :

end=3
declare -a 'range=({'"1..$end"'})'

Bây giờ chúng ta có một dãy số đẹp:

for i in ${range[@]};do echo $i;done
1
2
3

Đã thử nghiệm trong bash 4.3.11 nhưng nên hoạt động trong tất cả các phiên bản hiện đại.


chỉ là một đoạn cú pháp tôi đã sử dụng: read line; declare -a "l=($line)"; echo ${l[@]}- Tôi đã đặt nó để cho phép người dùng nhập chuỗi mở rộng dấu ngoặc và xem kết quả (trong một loại hướng dẫn bash).
gluk47

1
Trong thực tế, đó là như thế eval, nó không ít nguy hiểm hơn eval. Với end='$(reboot)', rebootlà chạy giống nhau.
Stéphane Chazelas

2

Một kỹ thuật khác bạn có thể sử dụng trong bash và một số shell khác là sử dụng một mảng:

$ extensions=(foo bar)
$ ls "${extensions[@]/#/1.}"

Đây là hình thức (thay thế mẫu) của mở rộng tham số. (Thật không may, điều này cũng không tuân thủ POSIX.) Việc chỉ định rằng việc thay thế nên được áp dụng cho từng phần tử của mảng và nên duy trì sự tách biệt giữa các phần tử.  trong một chuỗi mẫu hoạt động như một biểu thức chính quy (nghĩa là hầu hết các thay thế); điều đó có nghĩa là sự thay thế chỉ xảy ra ở đầu các giá trị tham số. Vì thế${parameter/pattern/string}[@]#^s/old/new/

$ ls "${extensions[@]/#/1.}"

tương đương với

$ ls "$ {phần mở rộng [ 0 ] / # / 1.}" "$ {phần mở rộng [ 1 ] / # / 1.}"

(vì mảng này có hai phần tử, được lập chỉ mục là 0 và 1) và điều này mở rộng thành

$ ls "1.foo" "1.bar"

Trích dẫn

Các trích dẫn rất quan trọng nếu các tiện ích mở rộng của Phần cứng, yêu cầu các trích dẫn - nghĩa là, nếu chúng (có thể, có thể, bao giờ) chứa các khoảng trắng hoặc ký tự mở rộng tên đường dẫn (global / wildcard). Ví dụ, nếu

$ extensions=("foo bar" "*r")

sau đó

$ ls ${extensions[@]/#/1.}

(không có dấu ngoặc kép) sẽ mở rộng sang

$ ls 1.foo bar 1.*r

(trong đó 1.foobarlà các đối số riêng biệt), và đến lượt nó, mở rộng thành

$ ls 1.foo bar 1.anteater 1.bar 1.bear 1.cougar 1.deer 1.grasshopper 

(vì 1.*rlà một ký tự đại diện không được trích dẫn). Để thảo luận thêm về tầm quan trọng của việc trích dẫn, hãy xem Hàm ý bảo mật của việc quên trích dẫn một biến trong các vỏ bash / POSIX .

Bạn cũng có thể khớp phần cuối của chuỗi bằng cách sử dụng %trong mẫu :

$ fnames=(cat dog)
$ ls "${fnames[@]/%/.c}"

mở rộng đến

$ ls "cat.c" "dog.c"

Nhưng hãy cẩn thận: % không hoạt động giống như $trong các biểu thức thông thường. Bạn cần phải đặt nó ở đầu của mô hình để chế ngự trận đấu xảy ra ở phần cuối của các giá trị tham số. Ví dụ, nếu bạn có

$ fnames=(cat.c dog.c)

và bạn muốn có được cat.odog.o, đừng làm "${fnames[@]/.c%/.o}" - nó sẽ không hoạt động. Làm

$ ls "${fnames[@]/%.c/.o}"

Nhưng đừng làm "${fnames[@]/.c/.o}"(bỏ %hoàn toàn) hoặc - nếu một trong những tên trong số đó là dog.catcher.c, thì nó sẽ được chuyển đổi thành (vì cái đầu tiên được thay thế bằng ).dog.oatcher.c .c.o

Thật không may, không có cách dễ dàng để thêm tiền tố và hậu tố, như bạn có thể làm với

$ ls 1.{foo,bar}.c

Xem tài liệu bash để biết thêm thông tin về các biến, mảng và các phép biến đổi bạn có thể áp dụng cho chúng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.