Lệnh sau được sử dụng để tìm kiếm số điện thoại gồm 7 chữ số:
grep "[[:digit:]]\{3\}[ -]\?[[:digit:]]\{4\}" file
Không đại diện \?
cho cái gì?
Lệnh sau được sử dụng để tìm kiếm số điện thoại gồm 7 chữ số:
grep "[[:digit:]]\{3\}[ -]\?[[:digit:]]\{4\}" file
Không đại diện \?
cho cái gì?
Câu trả lời:
Nó giống như ?
trong nhiều công cụ biểu thức chính quy khác, và có nghĩa là "khớp 0 hoặc bất kỳ thứ gì xuất hiện trước nó".
Trong ví dụ của bạn, cái \?
được áp dụng cho [ -]
, nghĩa là nó cố khớp một khoảng trắng hoặc dấu trừ, nhưng khoảng trắng hoặc dấu trừ là tùy chọn.
Vì vậy, bất kỳ trong số này sẽ phù hợp:
555 1234
555-1234
5551234
Lý do nó được viết \?
thay vì ?
là để tương thích ngược.
Phiên bản gốc đã grep
sử dụng một loại biểu thức chính quy khác được gọi là "biểu thức chính quy cơ bản" trong đó ?
chỉ có nghĩa là một dấu hỏi theo nghĩa đen.
Vì vậy, GNU grep có thể có chức năng 0 hoặc 1, họ đã thêm nó, nhưng phải sử dụng \?
cú pháp để các tập lệnh được sử dụng ?
vẫn hoạt động như mong đợi.
Lưu ý rằng grep có một -E
tùy chọn làm cho nó sử dụng loại biểu thức chính quy phổ biến hơn, được gọi là "biểu thức chính quy mở rộng".
man 1 grep
:
-E, --extended-regexp
Interpret PATTERN as an extended regular expression
(ERE, see below). (-E is specified by POSIX.)
-G, --basic-regexp
Interpret PATTERN as a basic regular expression (BRE, see below).
This is the default.
...
Repetition
A regular expression may be followed by one of several repetition operators:
? The preceding item is optional and matched at most once.
...
grep understands three different versions of regular expression syntax:
“basic,” “extended” and “perl.”
...
Basic vs Extended Regular Expressions
In basic regular expressions the meta-characters ?, +, {, |, (, and )
lose their special meaning; instead use the backslashed versions
\?, \+, \{, \|, \(, and \).
Thêm thông tin:
grep -E
là cách POSIX chính thức. egrep
đã bị phản đối trong susv2 (1997) và bị xóa trong susv3 (2001) khỏi thông số kỹ thuật POSIX và Unix.
\?
là một GNUism mặc dù.
Thật không may, cú pháp chính xác của biểu thức chính quy thay đổi đôi chút giữa các chương trình khác nhau: grep regexes không hoàn toàn giống với biểu thức sed, không giống hệt như biểu thức Emacs, không giống hệt như biểu thức C ++, và vì vậy trên. Để làm cho vấn đề tồi tệ hơn, ngay cả một công cụ "tiêu chuẩn" như grep cũng có thể thay đổi đôi chút giữa các hệ điều hành giống Unix khác nhau.
Trong một biểu thức chính tả, một số ký tự có ý nghĩa đặc biệt (chẳng hạn như dấu ngoặc vuông trong ví dụ của bạn) và trở lại nghĩa bình thường của chúng là ký tự chữ khi bạn "thoát" chúng bằng cách đặt dấu gạch chéo ngược trước chúng (vì vậy dấu ngoặc sẽ là Viết như \[). Những người khác làm việc theo cách khác và chỉ mang ý nghĩa đặc biệt khi thoát (ví dụ: n đơn giản chỉ là một chữ cái, nhưng \ n là một nguồn cấp dữ liệu). Và những điều này, một lần nữa, có thể khác nhau giữa các triển khai regex.
Trong hầu hết các triển khai regex, một dấu hỏi có nghĩa là mục trước đó là tùy chọn, trong khi dấu hỏi thoát (\?) Là dấu chấm hỏi theo nghĩa đen. Nhưng trong một số phương ngữ, đó là cách khác. Ví dụ của bạn có thể có ý nghĩa xung quanh, nhưng tôi nghi ngờ bạn có một trong những phương ngữ ở đâu? là một nghĩa đen và \? là biểu tượng tùy chọn. Vì vậy, regex của bạn có thể có nghĩa là "ba chữ số, theo sau là dấu cách hoặc dấu gạch ngang, theo sau là bốn chữ số".
(Một manh mối khác có thể được nhìn thấy trong các cấu trúc như \ {3 \}, rõ ràng có nghĩa là "chính xác 3 mục trước". Trong hầu hết các phương ngữ regex, điều này sẽ được viết {3} và \ {sẽ là một dấu ngoặc .)
Đây là một bản tóm tắt nhanh chóng về thông tin đã có trong các câu trả lời khác.
Trong grep
, ?
khớp với một ký tự dấu chấm hỏi theo nghĩa đen và \?
biểu thị số không hoặc một lần xuất hiện của bất cứ điều gì xảy ra trước nó. Vì vậy, trong ví dụ trong câu hỏi của bạn, [ -]\?
khớp với dấu cách hoặc dấu gạch nối hoặc không có gì.
Trong egrep
hoặc grep -E
, đó là cách khác xung quanh; \?
khớp với một dấu hỏi theo nghĩa đen và ?
biểu thị số không hoặc một lần xuất hiện.
Điều này áp dụng cho GNU grep; các chi tiết cho việc triển khai grep không phải GNU có thể khác nhau đôi chút. Đặc biệt, grep
và trong egrep
lịch sử là hai chương trình riêng biệt và tôi không nghĩ rằng những cái cũ grep
có -E
tùy chọn. POSIX không chỉ định grep -E
, nhưng (tôi rất ngạc nhiên khi phát hiện ra) không đề cập đến egrep
.
egrep
lệnh tương đương vớigrep -E
. Đối với các phiên bản không phải là GNU grep,grep
có thể hoặc không thể chấp nhận-E
tùy chọn này vàegrep
có thể là một chương trình riêng biệt.