bash kết hợp mở rộng ký tự đại diện với mở rộng cú đúp


8

Tôi đang cố gắng mở rộng chuỗi liên quan đến ký tự đại diện và bộ sưu tập các tiện ích mở rộng được chỉ định trong dấu ngoặc nhọn. Dường như không có gì hoạt động như ví dụ dưới đây minh họa. biến firstListmở rộng tốt, nhưng không secondList, thirdListhoặc fourthListmở rộng đúng. Tôi cũng đã thử các phiên bản khác nhau evalnhưng không có phiên bản nào hoạt động. Bất kỳ trợ giúp sẽ được đánh giá cao

#!/bin/bash
touch a.ext1
touch b.ext1
firstList='*.ext1'
ls  $firstList
touch a.ext2
touch b.ext2
secondList='*.{ext1,ext2}'
ls $secondList 
ls '$secondList'
ls "$secondList"
thirdList=*.{ext1,ext2}
ls $thirdList  
ls '$thirdList'
ls "$thirdList"
fourthList="*.{ext1,ext2}"
ls $fourthList
ls '$fourthList'
ls "$fourthList"

fwiw eval ls $secondListhoạt động tốt ở đây ... bạn đang cố gắng đạt được điều gì?
don_crissti

Bạn cần kiểm tra thứ tự mở rộng bash - mở rộng niềng răng xảy ra trước khi mở rộng paramater. Để có được hiệu quả mà bạn hy vọng, bạn cần evalcó được vòng 2 mở rộng.
glenn jackman


@glennjackman Có một giải pháp không có eval. Nhìn vào giải pháp thứ hai ở cuối câu trả lời của tôi .

Câu trả lời:


7

Các vỏ mở rộng *chỉ khi un-trích dẫn, bất kỳ điểm dừng trích dẫn mở rộng bằng vỏ.

Ngoài ra, một mở rộng cú đúp cần phải được bỏ qua để được mở rộng bởi vỏ.

Công việc này (cho phép sử dụng echo để xem shell làm gì):

$ echo *.{ext1,ext2}
a.ext1 b.ext1 a.ext2 b.ext2

Ngay cả khi có các tệp có một số tên khác:

$ touch {a,b}.{ext1,ext2} {c,d}.{ext3,ext4} none
ls
a.ext1  a.ext2  b.ext1  b.ext2  c.ext3  c.ext4  d.ext3  d.ext4  none

$ echo *.{ext1,ext2}
a.ext1 b.ext1 a.ext2 b.ext2

Tại sao điều đó làm việc?

Điều quan trọng là chúng tôi hiểu lý do tại sao điều đó làm việc. Đó là vì thứ tự mở rộng. Đầu tiên là "Mở rộng cú đúp" và sau đó (lần cuối cùng) "Mở rộng tên đường" (hay còn gọi là mở rộng toàn cầu).

Brace --> Parameter (variable) --> Pathname

Chúng tôi có thể tắt "Mở rộng tên đường dẫn" trong giây lát:

$ set -f
$ echo *.{ext1,ext2}
*.ext1 *.ext2

"Mở rộng tên đường dẫn" nhận được hai đối số: *.ext1*.ext2.

$ set +f
$ echo *.{ext1,ext2}
a.ext1 b.ext1 a.ext2 b.ext2

Vấn đề là chúng ta không thể sử dụng một biến để mở rộng niềng răng.
Nó đã được giải thích nhiều lần trước khi sử dụng một biến trong "Mở rộng cú đúp"

Để mở rộng "Mở rộng cú đúp" là kết quả của "Mở rộng biến", bạn cần gửi lại dòng lệnh cho trình bao với eval.

$ list={ext1,ext2}
$ eval echo '*.'"$list"

Cú đúp -> Biến -> Glob | | -> Cú đúp -> Biến -> Glob
........ được trích dẫn ở đây -> ^^ ^ ^ ^ ^ ^ ^ | eval ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^

Giá trị của tên tệp không mang lại vấn đề thực thi cho eval:

$ touch 'a;date;.ext1'
eval echo '*.'"$list"
a;date;.ext1 a.ext1 b.ext1 a.ext2 b.ext2

Nhưng giá trị của $listcó thể không an toàn. Tuy nhiên, giá trị của $listđược đặt bởi người viết kịch bản. Người viết kịch bản kiểm soát eval: Chỉ không sử dụng các giá trị được đặt bên ngoài cho $list. Thử cái này:

#!/bin/bash
touch {a,b,c}.ext{1,2}
list=ext{1,2}
eval ls -l -- '*.'"$list"

Một sự thay thế tốt hơn.

Một cách khác (không có eval) là sử dụng Bash "Các mẫu mở rộng" :

#!/bin/bash
shopt -s extglob
list='@(ext1|ext2)'
ls -- *.$list

Lưu ý: Xin lưu ý rằng cả hai giải pháp (eval và mẫu) (như được viết) đều an toàn cho tên tệp có dấu cách hoặc dòng mới. Nhưng sẽ thất bại cho a $listvới khoảng trắng, vì không $listđược trích dẫn hoặc eval xóa dấu ngoặc kép.


Có, mở rộng toàn cầu
glenn jackman

2

Xem xét:

secondList='*.{ext1,ext2}'
ls $secondList 

Vấn đề là mở rộng cú đúp được thực hiện trước khi mở rộng biến . Điều đó có nghĩa là, trong phần trên, mở rộng cú đúp không bao giờ được thực hiện.

Điều này là do, khi bash lần đầu tiên nhìn thấy dòng lệnh, không có dấu ngoặc nhọn. Sau khi secondListđược mở rộng thì đã quá muộn.

Sau đây sẽ hoạt động:

$ s='*'
$ ls $s.{ext1,ext2}
a.ext1  a.ext2  b.ext1  b.ext2

Ở đây, dòng lệnh có dấu ngoặc để mở rộng dấu ngoặc có thể thực hiện như bước đầu tiên. Sau đó, giá trị của $sđược thay thế trong ( mở rộng biến ) và cuối cùng là mở rộng tên đường dẫn được thực hiện.

Tài liệu

man bash giải thích thứ tự mở rộng:

Thứ tự mở rộng là: mở rộng cú đúp; mở rộng dấu ngã, mở rộng tham số và biến, mở rộng số học và thay thế lệnh (được thực hiện theo kiểu từ trái sang phải); tách từ; và mở rộng tên đường dẫn.

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.