Bash = ~ regex và https://regex101.com/


12

Sử dụng https://regex101.com/ Tôi đã tạo một biểu thức chính quy để trả về lần xuất hiện đầu tiên của địa chỉ IP trong chuỗi.

RegExp:

(?:\d{1,3}\.)+(?:\d{1,3})

RegExp bao gồm các dấu phân cách:

/(?:\d{1,3}\.)+(?:\d{1,3})/

Với chuỗi kiểm tra sau:

eu-west                       140.243.64.99 

Nó trả về một trận đấu đầy đủ của:

140.243.64.99

Bất kể tôi cố gắng gì với neo, v.v., tập lệnh bash sau sẽ không hoạt động với biểu thức thông thường được tạo.

temp="eu-west                       140.243.64.99            "
regexp="(?:\d{1,3}\.)+(?:\d{1,3})"
if [[ $temp =~ $regexp ]]; then
  echo "found a match"
else
  echo "No IP address returned"
fi

3
Trông giống như một biểu hiện thường xuyên của Perl đối với tôi. Bash không ủng hộ điều đó.
Kusalananda

1
Các =~nhà điều hành sẽ được thảo luận ở đây trong cuốn hướng dẫn nơi nó được viết sử dụng bash "biểu thức thông thường kéo dài". Regexes mở rộng được mô tả trong regex(7)trang người đàn ông và tóm tắt ngắn gọn ở đây .
glenn jackman

Câu trả lời:


15

\dlà một cách không chuẩn để nói "bất kỳ chữ số". Tôi nghĩ rằng nó đến từ Perl, và rất nhiều ngôn ngữ và tiện ích khác cũng hỗ trợ RE tương thích với Perl (PCRE). (và ví dụ GNU grep 2.27 trong Debian Stretch hỗ trợ tương tự \wcho các ký tự từ ngay cả trong chế độ bình thường.)

Bash không hỗ trợ \d, tuy nhiên, vì vậy bạn cần sử dụng rõ ràng [0-9]hoặc [[:digit:]]. Tương tự cho nhóm không chụp (?:..), chỉ sử dụng (..)thay thế.

Điều này sẽ in match:

temp="eu-west                       140.243.64.99            "
regexp="([0-9]{1,3}\.)+([0-9]{1,3})"
[[ $temp =~ $regexp ]] && echo match

2
GNU của bạn có grephỗ trợ \dmà không có -P?
Stéphane Chazelas

@ StéphaneChazelas, rất tiếc, tất nhiên là không. Nó hỗ trợ \w\b, điều mà tôi đã học được từ Perl, vì vậy tôi đã nhầm lẫn điều đó.
ilkkachu

thật không công bằng khi nói \dhoặc PCRE là "không chuẩn". Chúng khá chuẩn, chỉ là một tiêu chuẩn khác với các biểu thức chính quy ban đầu và các biểu thức chính quy mở rộng.
Daniel Farrell

1
@DanielFarrell, tiêu chuẩn trong trường hợp này là những gì POSIX chỉ định và nó không biết về nó \d. Mặc dù bạn đúng trong PCRE đó là khá chuẩn hoặc ít được xác định rõ nhất. Vấn đề gây phiền nhiễu là GNU grep (hoặc glibc) hỗ trợ một số PCRE giống như nguyên tử, ít nhất \w\skhi giải thích ERE, và trong bối cảnh đó họ rất nhiều không chuẩn. Phrasing của tôi có thể xuất phát một phần từ đó, và sự đánh giá sai \dđược hỗ trợ tương tự GNU.
ilkkachu

4

(:...)\dlà các toán tử biểu thức chính quy perl hoặc PCRE (như trong GNU grep -P).

bashchỉ hỗ trợ các biểu thức chính quy mở rộng như grep -Engoại trừ cho các biểu thức chính được chuyển theo nghĩa đen [[ text =~ regexp-here ]]trái ngược với kết quả của việc mở rộng không được trích dẫn (như trong [[ text =~ $var ]]hoặc [[ test =~ $(printf '%s\n' 'regexp-here') ]]), nó bị giới hạn trong bộ tính năng biểu thức chính quy mở rộng POSIX.

Vì vậy, ngay cả trên các hệ thống grep -E '\d'sẽ hoạt động (GNU ERE đã nhập một số tiện ích mở rộng từ các biểu thức chính quy như \svậy, các phiên bản trong tương lai cũng có thể có \d), bạn phải sử dụng:

regexp='\d'
[[ $text =~ $regexp ]]

trong bashđó để làm việc ( [[ $text =~ \d ]]sẽ không).

Đối với hệ vỏ hỗ trợ PCRE, bạn có thể muốn sử dụng zshthay thế:

set -o rematchpcre
[[ $text =~ '(?:\d{1,3}\.)+(?:\d{1,3})' ]]

ksh93 cũng hỗ trợ thực hiện riêng các biểu thức chính quy giống như perl (không tương thích hoàn toàn) như là một phần của khớp mẫu. Ở đó, bạn sẽ sử dụng:

regexp='~(P)(?:\d{1,3}\.)+(?:\d{1,3})'
[[ $text = $regexp ]]

(lưu ý =thay vì =~. Bạn sẽ muốn sử dụng các biến tạm thời vì nó rất có lỗi khi bạn không)


1

Trang regex101.com sử dụng PCRE (nhìn ở góc trên bên trái) làm mặc định và nó thiếu hỗ trợ cho cú pháp regex "Mở rộng". Đó là "Expresions thường xuyên tương thích Perl", xuất hiện (như là hợp lý để mong đợi) từ Perl.

PCRE được hỗ trợ bởi một số công cụ (như grep -P) trong một số điều kiện, nhưng hỗ trợ regex bash bên trong [[…]]thành ngữ chỉ dành cho regex mở rộng (như grep -E).

Trong regex mở rộng, (?…)dấu ngoặc đơn không bắt giữ không tồn tại và \ d cũng bị thiếu. Bạn cần sử dụng đơn giản (…)[0-9]:

regexp="([0-9]{1,3}\.)+([0-9]{1,3})"
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.