Sự khác biệt giữa `a [bc] d` (ngoặc) và` a {b, c} d` (niềng răng) là gì?


28

Sự khác biệt giữa a[bc]dvà là a{b,c}dgì? Tại sao mọi người sử dụng a{b,c}dkhi đã có a[bc]d?


Ai bảo bạn dùng command a[bc]d?
Jesse_b

3
Nó chắc chắn có công dụng của nó nếu một người hiểu chính xác.
Weijun Zhou

7
Tôi đoán là tôi không hiểu sự nhầm lẫn giữa hai người đã xảy ra như thế nào.
Jesse_b

Tôi đã được hỏi một cách rõ ràng bởi một đồng nghiệp ít quen thuộc với Linux về điều này, mặc dù không phải gần đây.
Weijun Zhou

@Jesse_b Nếu bạn chỉ từng thử chúng với các thao tác trên các tệp như lsvà bạn chỉ từng thử các ký tự đơn, chúng sẽ xuất hiện để hoạt động như nhau.
Nacht - Tái lập Monica

Câu trả lời:


43

Hai người khá khác nhau.

a[bc]dlà 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 abdacdnế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 adtrong tên tệp phải là a bhoặc a c.

  • Nếu abdtồn tại, nhưng acdkhông, thì nó sẽ chỉ mở rộng ra abdvà ngược lại.

  • Nếu không abd, cũng không acdtồ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 fishUnix gốc sh(t)cshnếu có các khối phù hợp khác trong cùng một lệnh).

a{b,c}dlà 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 abdacd.

  • 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..khoặc các chuỗi 20..25nâng cao hơn như 00..20..2hoặ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 ad. 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]dcó 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.


Cảm ơn bạn đã làm rõ "Nếu abd tồn tại, nhưng acd không có, thì nó sẽ chỉ mở rộng thành abd". Tôi đoán đó là những gì còn thiếu từ câu trả lời của tôi.
Weijun Zhou

9
Một sự khác biệt quan trọng khác là a{b,c}d, trong bcphầ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]sionhoặc bất cứ điều gì sẽ chỉ phù hợp với một trong những chữ cái này.
alexis

7

a[bc]dmô 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ư abdhoặc a/d. Nó chỉ phù hợp với một tên đường dẫn theo nghĩa đen a[b/c]d.

a{b,c}dmở 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 cshnhưng hành vi trong bashkhác với cshvà 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 bash3.0 và được bổ sung thêm trong bash4.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]dsẽ ít gặp khó khăn hơn khi nhập. Ví dụ grep pattern [ab][12].txt.


2
Việc mở rộng cú đúp không phải là "bashism"; nó lần đầu tiên xuất hiện trong 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 bashnó đượ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.
mosvy

Cảm ơn bạn. Tôi sẽ cập nhật câu trả lời.
Weijun Zhou
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.