Sự khác biệt giữa a[bc]d
và là a{b,c}d
gì? Tại sao mọi người sử dụng a{b,c}d
khi đã có a[bc]d
?
ls
và bạn chỉ từng thử các ký tự đơn, chúng sẽ xuất hiện để hoạt động như nhau.
Sự khác biệt giữa a[bc]d
và là a{b,c}d
gì? Tại sao mọi người sử dụng a{b,c}d
khi đã có a[bc]d
?
ls
và bạn chỉ từng thử các ký tự đơn, chúng sẽ xuất hiện để hoạt động như nhau.
Câu trả lời:
Hai người khá khác nhau.
a[bc]d
là một mẫu tên tệp (trong shell khác fish
). Nó sẽ mở rộng thành hai tên tệp abd
và acd
nếu đó là tên của các tệp hiện có trong thư mục hiện tại.
Phần [...]
này là một biểu thức được đặt trong ngoặc khớp với một ký tự trong số các ký tự được liệt kê (hoặc các phần tử đối chiếu khi bao gồm các phạm vi). Để khớp với mẫu a[bc]d
, ký tự giữa các chuỗi a
và d
trong tên tệp phải là a b
hoặc a c
.
Nếu abd
tồn tại, nhưng acd
không, thì nó sẽ chỉ mở rộng ra abd
và ngược lại.
Nếu không abd
, cũng không acd
tồn tại, tùy thuộc vào vỏ và các tùy chọn, nó sẽ kích hoạt một lỗi (gốc Unix sh
, (t)csh
, zsh
, fish
, bash -O failglob
) và có thể thoát khỏi vỏ, hoặc rời khỏi unexpanded¹ mẫu (Bourne-like và rc
-like vỏ) hoặc mở rộng để không có gì ( bash/zsh/yash -o nullglob
, một số phiên bản cũ hơn của fish
Unix gốc sh
và (t)csh
nếu có các khối phù hợp khác trong cùng một lệnh).
a{b,c}d
là một mở rộng cú đúp (trong vỏ hỗ trợ những cái này). Nó sẽ mở rộng ra hai chuỗi abd
và acd
.
Phần {...}
này là một chuỗi các chuỗi được phân tách bằng dấu phẩy (trong ví dụ này; trong một số shell, nó cũng có thể là một phạm vi như a..k
hoặc các chuỗi 20..25
nâng cao hơn như 00..20..2
hoặc 0..20..2%02d
), và sự mở rộng được tính bằng cách kết hợp từng chuỗi này với sườn chuỗi a
và d
. Các chuỗi này có thể dài hơn một ký tự và cũng có thể là bản mở rộng cú đúp.
Việc mở rộng xảy ra bất kể các chuỗi này có tương ứng với tên tệp hiện có hay không.
Nếu bạn đang xây dựng chuỗi, sử dụng mở rộng cú đúp. Nếu bạn khớp tên tệp, hãy sử dụng mẫu tên tệp.
Trong trường hợp cụ thể này, a[bc]d
có thể là tên của một tệp hiện có, đó là lý do tại sao nó có thể nguy hiểm khi sử dụng những thứ như rm -f ./*.[ch]
trong các shell đó và rm -f ./*.{c,h}
ít gặp sự cố hơn.
a{b,c}d
, trong b
và c
phần không cần phải là các chữ cái đơn lẻ; ví dụ ex{ten,ci}sion
. Trong khi ex[tenci]sion
hoặc bất cứ điều gì sẽ chỉ phù hợp với một trong những chữ cái này.
a[bc]d
là mô hình khớp , và là một phần của tiêu chuẩn POSIX. Trong POSIX, điều này được giới thiệu là "biểu thức khung mẫu". Nó được ghi lại trong phần 2.13 của tài liệu hướng dẫn
Khi không được trích dẫn và bên ngoài một biểu thức ngoặc, ba ký tự sau sẽ có ý nghĩa đặc biệt trong đặc tả của các mẫu:
?
Dấu hỏi là một mẫu phù hợp với bất kỳ ký tự nào.
*Dấu hoa thị là một mẫu sẽ khớp với nhiều ký tự, như được mô tả trong Mẫu khớp với nhiều ký tự.
[Dấu ngoặc mở sẽ giới thiệu một biểu thức khung mẫu.
Mục 2.13.3 cũng đề cập đến một cái gì đó mà nó hoạt động khác với những gì người ta mong đợi đối với các biểu thức chính quy thông thường khi nó được sử dụng để mở rộng tên tệp (nhấn mạnh bởi tôi)
Các quy tắc được mô tả cho đến nay trong Các mẫu khớp với một ký tự đơn và các mẫu khớp với nhiều ký tự được đủ điều kiện theo các quy tắc sau áp dụng khi ký hiệu khớp mẫu được sử dụng để mở rộng tên tệp:
Ký tự gạch chéo trong tên đường dẫn phải được khớp rõ ràng bằng cách sử dụng một hoặc nhiều dấu gạch chéo trong mẫu; nó sẽ không được khớp với các ký tự đặc biệt dấu hoa thị hoặc dấu chấm hỏi cũng như biểu thức ngoặc. Dấu gạch chéo trong mẫu phải được xác định trước biểu thức ngoặc; do đó, một dấu gạch chéo không thể được bao gồm trong biểu thức khung mẫu được sử dụng để mở rộng tên tệp. Nếu một ký tự gạch chéo được tìm thấy sau một ký tự dấu ngoặc vuông mở không thoát ra trước khi tìm thấy dấu ngoặc vuông đóng tương ứng, dấu ngoặc mở sẽ được coi là một ký tự bình thường. Ví dụ, mẫu
"a[b/c]d"
không khớp với các tên đường dẫn nhưabd
hoặca/d
. Nó chỉ phù hợp với một tên đường dẫn theo nghĩa đena[b/c]d
.
a{b,c}d
là mở rộng niềng răng , nó không nằm trong đặc tả của POSIX. Đây là phần tương ứng từ hướng dẫn bash (nhấn mạnh bởi tôi):
Mở rộng cú đúp là một cơ chế theo đó các chuỗi tùy ý có thể được tạo ra. Cơ chế này tương tự như mở rộng tên tệp (xem Mở rộng tên tệp), nhưng tên tệp được tạo không cần tồn tại . Các mẫu được niềng răng mở rộng có dạng một phần mở đầu tùy chọn , theo sau là một chuỗi các chuỗi được phân tách bằng dấu phẩy hoặc một biểu thức chuỗi giữa một cặp dấu ngoặc, theo sau là một phần tái bút tùy chọn . Lời mở đầu được tiền tố cho mỗi chuỗi có trong dấu ngoặc nhọn và sau đó phần tái bút được thêm vào từng chuỗi kết quả, mở rộng từ trái sang phải.
Theo nhận xét của @mosvy, lần đầu tiên này xuất hiện csh
nhưng hành vi trong bash
khác với csh
và các vỏ khác. Loại mở rộng niềng răng này cũng có mặt trong glob(3)
.
Có một loại mở rộng niềng răng {a..z}
khác chỉ xuất hiện sau bash
3.0 và được bổ sung thêm trong bash
4.0.
Trong một vỏ nơi bật tính năng Globing, thực thi trong một thư mục trống, kết quả sau được trả về
$ echo a[bc]d
a[bc]d
$ echo a{b,c}d
abd acd
Đáp lại bình luận của @ Jesse_b, nếu bạn đang ở trong một vỏ tương tác và cả hai đều áp dụng, a[bc]d
sẽ ít gặp khó khăn hơn khi nhập. Ví dụ grep pattern [ab][12].txt
.
csh
, rất lâu trước đó bash
. Nó cũng có mặt trong chức năng thư viện toàn cầu (3). Sự khác biệt là trong bash
nó được thực hiện trước các bản mở rộng khác: a=A; ab=A/B; ac=A/C; echo $a{b,c}
sẽ hoạt động trong bash khác với bất kỳ shell nào khác.
command a[bc]d
?