Проверка на коректността на имейл адрес с регулярен израз в Bash

Опитвам се да направя Bash скрипт, за да проверя дали даден имейл адрес е правилен.

Имам този регулярен израз:

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

Източник: http://www.regular-expressions.info/email.html

И това е моят bash скрипт:

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

Скриптът се проваля и ми дава този резултат:

10: Синтактична грешка: EOF при заместване на обратни кавички

Някаква следа??


person ballstud    schedule 26.01.2010    source източник
comment
Знаете ли за интернационализирани имена на домейни icann.org/en/topics/idn? вашият регулярен израз съвпада ли с test@fõõ.bâr.com?   -  person Jean    schedule 26.01.2010
comment
Ако прочетете внимателно тази статия, която цитирахте, ще видите, че а) регулярните изрази ще ви помогнат само да сортирате очевидно незаконни адреси, б) ще имате или фалшиви положителни резултати и фалшиви отрицания, или напълно тромав регулярен израз, и в) в накрая ще трябва действително да изпратите имейл до този адрес, за да проверите дали е не само синтактично валиден, но и всъщност правилен (което никой регулярен израз не може да ви каже).   -  person Tim Pietzcker    schedule 26.01.2010
comment
вижте тази публикация: solidlystated.com/scripting/proper-email-address-validation   -  person Nam Nguyen    schedule 30.10.2013
comment
свързани stackoverflow.com/questions/201323/   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 16.05.2016


Отговори (8)


Тук имате няколко проблема:

  • Регулярният израз трябва да бъде поставен в кавички и специалните символи да бъдат екранирани.
  • Регулярният израз трябва да бъде закотвен (^ и $).
  • ?: не се поддържа и трябва да бъде премахнат.
  • Имате нужда от интервали около оператора =~.

Краен продукт:

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
person Peter Eisentraut    schedule 26.01.2010
comment
Бих искал обаче да добавя, че правенето на това в bash е доста, хм, неоптимално. Но исках да подчертая как да коригирам подхода, който сте избрали. - person Peter Eisentraut; 26.01.2010
comment
този регулярен израз се провали, когато тествах в Ubuntu 13, но премина в Ubuntu 12 - person Nam Nguyen; 30.10.2013
comment
този регулярен израз работи за мен: regex=^[a-zA-Z0-9\._-]+\@[a-zA-Z0-9._-]+\.[a-zA-Z]+\$ - person Horst; 25.03.2021
comment
Имайте предвид, че отговорът на @PeterEisentraut не работи за имейл адреси, които имат главни букви, които все още са валидни. - person Matthew Knill; 11.06.2021

Не е нужно да създавате толкова сложен регулярен израз, за ​​да проверите валиден имейл. Можете просто да разделите на "@", след което да проверите дали има 2 елемента, единият, който е пред @, а другият отзад.

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

За да проверите домейна допълнително, можете да използвате инструменти като dig, за да направите заявка за домейна. По-добре е от regex, защото @new.jersey се съпоставя с regex, но всъщност не е правилен домейн.

person ghostdog74    schedule 26.01.2010
comment
Всъщност мисля, че това е много по-разумен подход. помислете за всички уебсайтове, които забраняват: [email protected], въпреки че това е напълно валиден имейл. трябва да се отърве от повечето фалшификати и пак да е наред. можете да го направите малко по-силен, като проверите наличието на „.“ във втория елемент и се уверете, че разделя втория елемент на 2 поделемента. Помислете за пример за международни домейни - person Jean; 26.01.2010
comment
@Jean: вторият елемент също може да съдържа повече от два подниза, разделени с точка, така че това е добре, въпреки че бихте могли да разрешите имейлите ligḱe user@localhost също в някои случаи - person rubo77; 10.08.2016

Кавичките, обратните отметки и други са специални символи в скриптовете на обвивката и трябва да бъдат екранирани, ако се използват като при присвояването на regex. Можете да избягвате специални знаци с обратни наклонени черти или да използвате единични кавички около регулярния израз, ако пропуснете единичните кавички, използвани в него.

Бих препоръчал да използвате по-прост регулярен израз като .*@.*, защото цялата сложност е безсмислена. [email protected] изглежда напълно добре и ще бъде приет от всеки регулярен израз, но все пак не съществува.

person sth    schedule 26.01.2010

Bash версия по-малка от 3.2:

if [[ "$email" =~ "^[A-Za-z0-9._%+-]+@[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, по-голяма или равна на 3.2:

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

Причините, поради които не трябва да използвате много специфичен регулярен израз, като вашия, са обяснени тук.

person rouble    schedule 19.04.2011
comment
това ще се провали за [email protected] с помощта на bash shell - person Nam Nguyen; 23.10.2013
comment
Във версия 3.2 на bash те промениха начина на работа на регулярните изрази. За да бъдете кратки, не искате кавичките в регулярния израз на условието. За справка stackoverflow.com/questions/218156/bash-regex-with-quotes - person rouble; 06.11.2013

Непосредственият проблем с вашия скрипт е, че трябва да коригирате цитирането:

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])?'

Този регулярен израз обаче не приема всички синтактично валидни имейл адреси. Дори да е така, не всички синтактично валидни имейл адреси могат да бъдат доставени.

Ако адресите за доставка са това, което ви интересува, тогава не се занимавайте с регулярен израз или други средства за проверка на синтаксиса: изпратете предизвикателство до адреса, който потребителят предоставя. Внимавайте да не използвате недоверен вход като част от извикване на команда! С sendmail стартирайте sendmail -oi -t и напишете съобщение в стандартния вход на процеса sendmail, напр.,

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
person Greg Bacon    schedule 26.01.2010

Веднъж в момент на лудост написах тази подпрограма на Perl въз основа на книгата Mastering Regular Expressions:

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});
person Community    schedule 19.04.2011

Коригирах горните примери, за да има уникална функция, която ще проверява валидността на адреса с regexp и ако домейнът действително съществува с dig, в противен случай ще върне грешка.

#!/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

Нищо специално.

person eagle1    schedule 27.03.2014

Закъснявам за партито, но адаптирах скрипт, за да прочета файл, съдържащ имейли, и да го филтрирам с помощта на RFC822 regex, списъци с правописни грешки в домейни, mx търсене (благодарение на eagle1 тук) и двусмислено филтриране на имейли.

Скриптът може да се използва като:

./emailCheck.sh /path/to/emailList

и създава два файла, филтрирания списък и двусмисления списък. И двете вече са изчистени от несъвместими с RFC822 адреси, имейл домейни, които нямат валидни MX домейни, и правописни грешки в домейни.

Скриптът може да бъде намерен тук: https://github.com/deajan/linuxscripts

Корекции и коментари са добре дошли :)

person Orsiris de Jong    schedule 30.03.2016