Проверка правильности адреса электронной почты с помощью регулярного выражения в 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
связанный 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 для запроса домена. Это лучше, чем регулярное выражение, потому что @new.jersey соответствует регулярному выражению, но на самом деле это не правильный домен.

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 - 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

Я изменил приведенные выше примеры, чтобы иметь уникальную функцию, которая проверяет правильность адреса с помощью регулярного выражения и, если домен действительно существует с помощью 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, списков опечаток домена, поиска mx (спасибо здесь eagle1) и неоднозначной фильтрации электронной почты.

Скрипт можно использовать как:

./emailCheck.sh /path/to/emailList

и создает два файла, отфильтрованный список и неоднозначный список. Оба уже очищены от адресов, не соответствующих RFC822, доменов электронной почты, у которых нет действительных доменов MX, и опечаток домена.

Скрипт можно найти здесь: https://github.com/deajan/linuxscripts

Поправки и комментарии приветствуются :)

person Orsiris de Jong    schedule 30.03.2016