2010-01-26 11 views
5

Tôi đang cố tạo một tập lệnh Bash để kiểm tra xem địa chỉ email có chính xác hay không.Kiểm tra tính chính xác của địa chỉ email với cụm từ thông dụng trong Bash

Tôi có biểu thức chính quy này:

[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])? 

Nguồn: http://www.regular-expressions.info/email.html

Và đây là kịch bản bash của tôi:

regex=[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])? 

i="[email protected]" 
if [[ $i=~$regex ]] ; then 
    echo "OK" 
else 
    echo "not OK" 
fi 

Các kịch bản thất bại và đưa cho tôi kết quả này:

10: Syntax error: EOF in backquote substitution

Bất kỳ đầu mối nào ??

+0

Bạn có biết về tên miền quốc tế hóa http://www.icann.org/en/topics/idn/? so sánh regexp của bạn [email protected]õõ.bâr.com? – Jean

+0

Nếu bạn đọc bài báo mà bạn trích dẫn kỹ lưỡng, bạn sẽ thấy rằng a) regexes sẽ chỉ giúp bạn phân loại các địa chỉ bất hợp pháp, b) bạn sẽ có dương tính giả và âm bản sai hoặc regex hoàn toàn khó sử dụng và c) cuối cùng, bạn sẽ phải gửi một email đến địa chỉ đó để kiểm tra xem nó không chỉ hợp lệ về cú pháp nhưng thực tế là đúng (không có regex nào có thể cho bạn biết). –

+0

xem bài đăng này: http://solidlystated.com/scripting/proper-email-address-validation/ –

Trả lời

5

Dấu ngoặc kép, dấu gạch chéo ngược và các ký tự khác là các ký tự đặc biệt trong tập lệnh trình bao và cần phải được thoát nếu chúng được sử dụng như trong việc gán regex. Bạn có thể thoát khỏi các ký tự đặc biệt với dấu gạch chéo ngược, hoặc sử dụng dấu nháy đơn xung quanh regex nếu bạn bỏ qua một dấu trích dẫn được sử dụng trong nó.

Tôi khuyên bạn nên sử dụng cụm từ thông dụng đơn giản hơn như .*@.* vì tất cả sự phức tạp là vô ích. [email protected] trông hoàn toàn ổn và sẽ được chấp nhận bởi bất kỳ cụm từ thông dụng nào, nhưng vẫn không tồn tại.

6

Bạn có một vài vấn đề ở đây:

  • Các biểu hiện thường xuyên cần phải được trích dẫn và ký tự đặc biệt trốn thoát.
  • Cụm từ thông dụng phải được neo (^$).
  • ?: không được hỗ trợ và cần phải bị xóa.
  • Bạn cần khoảng trắng xung quanh toán tử =~.

sản phẩm cuối cùng:

regex="^[a-z0-9!#\$%&'*+/=?^_\`{|}~-]+(\.[a-z0-9!#$%&'*+/=?^_\`{|}~-]+)*@([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]([a-z0-9-]*[a-z0-9])?\$" 

i="[email protected]" 
if [[ $i =~ $regex ]] ; then 
    echo "OK" 
else 
    echo "not OK" 
fi 
+0

Tôi muốn thêm, tuy nhiên, làm điều này trong bash là khá, um, suboptimal. Nhưng tôi muốn nêu bật cách khắc phục cách tiếp cận mà bạn đã chọn. –

+0

regex này không thành công khi tôi thử nghiệm trong Ubuntu 13 nhưng thông qua trong Ubuntu 12 –

5

bạn không cần phải tạo ra như một regex phức tạp để kiểm tra email hợp lệ. bạn có thể chia nhỏ trên "@", sau đó kiểm tra xem có 2 mục, một mục ở phía trước của @ và mục kia ở phía sau không.

i="[email protected]" 
IFS="@" 
set -- $i 
if [ "${#@}" -ne 2 ];then 
    echo "invalid email" 
fi 
domain="$2" 
dig $domain | grep "ANSWER: 1" 1>/dev/null && echo "domain ok" 

nếu bạn muốn kiểm tra thêm trên miền hợp lệ, bạn có thể sử dụng các công cụ như tìm cách truy vấn tên miền. Nó tốt hơn regex vì @ new.jersey được kết hợp bởi regex nhưng thực ra nó không phải là một miền thích hợp.

+1

Tôi thực sự nghĩ rằng đây là một cách tiếp cận tốt hơn nhiều. nghĩ về tất cả trang web không cho phép: [email protected] mặc dù đây là email hoàn toàn hợp lệ. nó sẽ loại bỏ hầu hết các hàng giả và vẫn ổn. bạn có thể làm cho nó mạnh hơn một chút bằng cách kiểm tra sự hiện diện của '.' trong phần tử thứ hai và đảm bảo nó tách phần tử thứ hai trong 2 phần tử con.Hãy suy nghĩ các tên miền quốc tế cho exemple – Jean

+0

@Jean: phần tử thứ hai cũng có thể chứa nhiều hơn hai chất nền được phân cách bằng dấu chấm, vì vậy điều này chỉ là tốt, mặc dù bạn có thể muốn cho phép thư ligḱe 'user @ localhost' cũng như trong một số trường hợp – rubo77

0

Vấn đề trước mắt với kịch bản của bạn là bạn cần phải sửa chữa các trích dẫn:

regex='[a-z0-9!#$%&'"'"'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'"'"'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?' 

Tuy nhiên, biểu thức chính quy này không chấp nhận tất cả các địa chỉ email cú pháp hợp lệ. Ngay cả khi nó đã làm, không phải tất cả các địa chỉ email hợp lệ cú pháp được phân phối.

Nếu địa chỉ có thể phân phối là những gì bạn quan tâm, thì đừng bận tâm với cụm từ thông dụng hoặc các phương pháp kiểm tra cú pháp khác: gửi một thách thức đến địa chỉ mà người dùng cung cấp. Cẩn thận không sử dụng đầu vào không đáng tin cậy như một phần của lệnh gọi! Với sendmail, hãy chạy sendmail -oi -t và viết thư tới đầu vào chuẩn của quy trình gửi thư, ví dụ:,

To: [email protected] 
From: [email protected] 
Subject: email address confirmation 

To confirm your address, please visit the following link: 

http://www.your.organization.invalid/verify/1a456fadef213443 
1

phiên bản Bash ít hơn 3.2:

if [[ "$email" =~ "^[A-Za-z0-9._%+-][email protected][A-Za-z0-9.-]+\.[A-Za-z]{2,4}$" ]] 
then 
    echo "Email address $email is valid." 
else 
    echo "Email address $email is invalid." 
fi 

Bash version greater than or equal to 3.2:

if [[ "$email" =~ ^[A-Za-z0-9._%+-][email protected][A-Za-z0-9.-]+\.[A-Za-z]{2,4}$ ]] 
then 
    echo "Email address $email is valid." 
else 
    echo "Email address $email is invalid." 
fi 

Những lý do tại sao bạn không nên sử dụng một regex rất cụ thể, như bạn có, được giải thích here.

+0

sẽ thất bại đối với [email protected] bằng bash shell –

+0

Trong phiên bản 3.2 của bash, chúng thay đổi cách thức hoạt động của regex. Để giữ cho nó ngắn, bạn không muốn báo giá trên phần regex của điều kiện. Để bạn tham khảo http://stackoverflow.com/questions/218156/bash-regex-with-quotes – rouble

0

Trong một khoảnh khắc điên rồ một lần, tôi đã viết chương trình con Perl này dựa trên Regular Expressions cuốn sách Mastering:

sub getRFC822AddressSpec 
{ 
    my ($esc, $space, $tab, $period) = ('\\\\', '\040', '\t', '\.'); 
    my ($lBr, $rBr, $lPa, $rPa)  = ('\[', '\]', '\(', '\)'); 
    my ($nonAscii, $ctrl, $CRlist) = ('\200-\377', '\000-\037', '\n\015'); 

    my $qtext  = qq{ [^$esc$nonAscii$CRlist] }; # within "..." 
    my $dtext  = qq{ [^$esc$nonAscii$CRlist$lBr$rBr] }; # within [...] 
    my $ctext  = qq{ [^$esc$nonAscii$CRlist()] }; # within (...) 
    my $quoted_pair = qq{ $esc [^$nonAscii] }; # an escaped char 
    my $atom_char = qq{ [^()$space<>\@,;:".$esc$lBr$rBr$ctrl$nonAscii] }; 
    my $atom  = qq{ $atom_char+  # some atom chars 
          (?!$atom_char) # NOT followed by part of an atom 
         }; 
    # rfc822 comments are (enclosed (in parentheses) like this) 
    my $cNested  = qq{ $lPa (?: $ctext | $quoted_pair)* $rPa }; 
    my $comment  = qq{ $lPa (?: $ctext | $quoted_pair | $cNested)* $rPa }; 

    # whitespace and comments may be scattered liberally 
    my $X   = qq{ (?: [$space$tab] | $comment)* }; 

    my $quoted_str = qq{ " (?: $qtext | $quoted_pair)* " }; 
    my $word  = qq{ (?: $atom | $quoted_str) }; 
    my $domain_ref = $atom; 
    my $domain_lit = qq{ $lBr (?: $dtext | $quoted_pair)* $rBr }; 
    my $sub_domain = qq{ (?: $domain_ref | $domain_lit) }; 
    my $domain  = qq{ $sub_domain (?: $X $period $X $sub_domain)* }; 
    my $local_part = qq{ $word (?: $X $period $X $word)* }; 
    my $addr_spec = qq{ $local_part $X \@ $X $domain }; 

    # return a regular expression object 
    return qr{$addr_spec}ox; 
} 

my $spec = getRFC822AddressSpec(); 
my $address = q{foo (Mr. John Foo) @ bar. example}; 
print "$address is an email address" if ($address =~ qr{$spec}); 
0

Tôi đã điều chỉnh các ví dụ trên có một chức năng duy nhất mà sẽ kiểm tra tính hợp lệ của địa chỉ với regexp và nếu miền thực sự tồn tại với đào, nếu không sẽ trả về lỗi.

#!/bin/bash 
#Regexp 
regex="^[a-z0-9!#\$%&'*+/=?^_\`{|}~-]+(\.[a-z0-9!#$%&'*+/=?^_\`{|}~-]+)*@([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]([a-z0-9-]*[a-z0-9])?\$" 

#Vars 
checkdig=0; 
checkreg=0; 
address=$1; 
maildomain=`echo $address | awk 'BEGIN { FS = "@" } ; { print $2 }'`; 

#Domain Check 
checkdns() { 
     echo $maildomain | awk 'BEGIN { FS = "@" } ; { print $2 }' | xargs dig $maildomain | grep "ANSWER: 0" 1>/dev/null || checkdig=1; 
} 

#Regexp 
checkreg() { 
     if [[ $address =~ $regex ]] ; 
       then checkreg=1; 
     fi 
} 

#Execute 
checkreg; 
checkdns; 

#Results 
if [ $checkreg == 1 ] && [ $checkdig == 1 ]; 
     then echo "OK"; 
     else echo "not OK"; 
fi 
#End 

Không có gì đặc biệt.

0

Bắt đầu muộn cho bữa tiệc, nhưng tôi đã chỉnh sửa tập lệnh để đọc tệp chứa email và lọc bằng cách sử dụng regex RFC822, danh sách tên miền typo, tra cứu mx (nhờ eagle1 tại đây) và lọc email không rõ ràng.

Các kịch bản có thể được sử dụng như:

./emailCheck.sh /path/to/emailList 

và tạo ra hai tập tin, danh sách lọc và danh sách mơ hồ. Cả hai đã được xóa khỏi các địa chỉ không tuân thủ RFC822, các miền email không có các miền MX hợp lệ và các lỗi chính tả tên miền.

Script có thể được tìm thấy ở đây: https://github.com/deajan/linuxscripts

sửa và ý kiến ​​được hoan nghênh :)