Hành vi bất ngờ với tiếng vang [[: chữ số:]]


Câu trả lời:


34

Bởi vì chúng là hai thứ khác nhau. Đây {1,2,3}là một ví dụ về mở rộng cú đúp . Cấu {1,2,3}trúc được mở rộng bằng vỏ , echothậm chí trước khi nhìn thấy nó. Bạn có thể thấy những gì xảy ra nếu bạn sử dụng set -x:

$ set -x
$ echo {1,2,3}
+ echo 1 2 3
1 2 3

Như bạn có thể thấy, lệnh echo {1,2,3}được mở rộng thành:

echo 1 2 3

Tuy nhiên, [[:digit:]]là một lớp nhân vật POSIX . Khi bạn đưa nó vào echo, shell cũng sẽ xử lý nó trước, nhưng lần này nó đang được xử lý như một shell toàn cầu . nó hoạt động tương tự như khi bạn chạy echo *sẽ in tất cả các tệp trong thư mục hiện tại. Nhưng [[:digit:]]là một vỏ toàn cầu sẽ phù hợp với bất kỳ chữ số. Bây giờ, trong bash, nếu một vỏ toàn cầu không khớp với bất cứ thứ gì, nó sẽ được mở rộng thành chính nó:

$ echo /this*matches*no*files
+ echo '/this*matches*no*files'
/this*matches*no*files

Nếu quả địa cầu khớp với thứ gì đó, nó sẽ được in:

$ echo /e*c
+ echo /etc
/etc

Trong cả hai trường hợp, echochỉ cần in bất cứ thứ gì mà vỏ bảo nó in, nhưng trong trường hợp thứ hai, vì quả cầu khớp với thứ gì đó ( /etc) nó được yêu cầu in thứ gì đó.

Vì vậy, vì bạn không có bất kỳ tệp hoặc thư mục nào có tên bao gồm chính xác một chữ số (đó là những gì [[:digit:]]sẽ khớp), toàn cầu được mở rộng thành chính nó và bạn nhận được:

$ echo [[:digit:]]
[[:digit:]]

Bây giờ, hãy thử tạo một tệp được gọi 5và chạy cùng một lệnh:

$ echo [[:digit:]]
5

Và nếu có nhiều hơn một tệp phù hợp:

$ touch 1 5       
$ echo [[:digit:]]
1 5

Đây là (sắp xếp) tài liệu man bashtrong phần giải thích các nullglobtùy chọn tắt hành vi này:

nullglob
    If  set,  bash allows patterns which match no files (see
    Pathname Expansion above) to expand to  a  null  string,
    rather than themselves.

Nếu bạn đặt tùy chọn này:

$ rm 1 5
$ shopt -s nullglob
$ echo [[:digit:]]  ## prints nothing

$ 

4
Xem thêm shopt -s failglobđể có được một hành vi hữu ích hơn tương tự như các shell hiện đại như zshhay fish.
Stéphane Chazelas

Tôi đồng ý với Stéphane, sử dụng failglob. nullglobcó thể gây ra sự cố không mong muốn, ví dụ: khi dán URL xảy ra có ?.
Kevin

1
Chắc chắn, tôi chỉ đề cập nullglobđể chứng minh rằng mô hình đang được giải thích như một quả địa cầu bằng vỏ.
terdon

14

{1,2,3}mở rộng cú đúp , nó mở rộng đến các từ được liệt kê mà không liên quan đến ý nghĩa của chúng.

[...]là một nhóm ký tự, được sử dụng trong mở rộng tên tệp (hoặc ký tự đại diện hoặc toàn cầu) tương tự như dấu hoa thị *và dấu hỏi ?. Nó phù hợp với bất kỳ ký tự đơn nào được liệt kê bên trong hoặc các ký tự là thành viên của các nhóm được đặt tên, chẳng hạn như [:digit:]nếu chúng được liệt kê. Hành vi mặc định của hầu hết các shell là để nguyên ký tự đại diện nếu không có tệp nào khớp với nó.

.

Vì thế:

$ bash -c 'echo [[:digit:]]'           # bash leaves it as-is
[[:digit:]]
$ zsh -c 'echo [[:digit:]]'            # zsh by default complains if no match
zsh:1: no matches found: [[:digit:]]
$ touch 1 3 d i g t
$ bash -c 'echo [[:digit:]]'           # now there are two matches
1 3                                    # note that d, i, g and t do NOT match

Nhưng vẫn:

$ bash -c 'echo {1,2,3}'
1 2 3

Cả hai đều được mở rộng bằng shell , không thành vấn đề nếu lệnh bạn đang chạy là ls, echohoặc rm. Cũng lưu ý rằng nếu một trong hai được trích dẫn, chúng sẽ không được mở rộng:

$ bash -c 'echo "[[:digit:]]"'         # even though matching files still exist
[[:digit:]]
$ bash -c 'echo "{1,2,3}"'
{1,2,3}

cảm ơn câu trả lời của bạn, tôi mới biết về linux vì vậy hãy hỏi tôi rằng echo có liên quan đến tập tin 1 3 như thế nào, chức năng của nó là in các đối số của nó để không tìm kiếm các tập tin theo hiểu biết của tôi
AbdAllah Talaat

1
@AbdAllahTalaat điều này không liên quan gì đến tiếng vang, thực sự. Shell (ví dụ bash) sẽ "mở rộng" [[:digit:]] trước khi chuyển nó sang echo, vì vậy echokhông bao giờ nhìn thấy [[:digit:]], nó chỉ nhìn thấy 1 3. Bạn có thể thấy điều này bằng hành động bằng cách chạy set -xsẽ in các lệnh thực tế đang chạy (chạy set +xđể tắt lại).
terdon

@AbdAllahTalaat, echokhông tìm kiếm tệp, trình bao , trước khi chạy echo.
ilkkachu

Đặc biệt là vì tôi nghĩ trong DOS / Windows, các tiện ích mở rộng các ký tự đại diện chứ không phải vỏ. (Tôi có thể sai)
ilkkachu

Xin lỗi các bạn Tôi đã chuyển câu trả lời đúng sang câu trả lời của tedron vì bình luận của anh ấy có ý nghĩa rằng bash là công việc không lặp lại ... câu trả lời của anh ấy cũng chứa ý nghĩa đó .. tất cả các bạn đã giúp tôi ... tôi ước nếu tôi có thể đặt câu trả lời đúng cho tất cả các câu trả lời và nhận xét của bạn
Abd ALLah Talaat

4

{1,2,3}(ví dụ và {1..3}đang mở rộng cú đúp . Họ được giải thích bởi vỏ trước khi thực hiện lệnh.

[[:digit:]]là mã thông báo khớp mẫu , nhưng bạn không sử dụng nó ở một vị trí có bất kỳ tệp nào khớp với mẫu đó. Nếu bạn sử dụng khớp mẫu không khớp, nó sẽ tự mở rộng:

$ echo [[:digit:]]; touch 3; echo [[:digit:]]
[[:digit:]]
3

Không, như các câu trả lời khác chỉ ra chính xác, mẫu được khớp với tên tệp.
Toby Speight
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.