How can I mask a list of e-mail addresses like:

John Doe <john.doe@gmail.com>
John Doe <johndoe@hotmail.net>
Jane Doe <j.doe@outlook.org>

... with sed (or awk) into something like:

John Doe <j******e@g***l.com>
John Doe <j*****e@h*****l.net>
Jane Doe <j***e@o*****k.org>

In other words: replace most of the e-mail address with asterisks but make it somehow recognizable by users who know the actual e-mail address.

  • just a note, jd@co.cc is a perfectly valid email address that, when thusly encoded, would be rendered as jd@co.cc... – Benjamin Staton Nov 20 '15 at 23:43

Another Perl version:

perl -pe 's/(<.)(.*)(@.)(.*)(.\..*>)/$1."*" x length($2).$3."*" x length($4).$5/e'


$ perl -pe 's/(<.)(.*)(@.)(.*)(.\..*>)/$1."*" x length($2).$3."*" x length($4).$5/e' foo
John Doe <j*******@g***l.com>
John Doe <j******@h*****l.net>
Jane Doe <j****@o*****k.org>

With sed, replacing the characters by an equal number of * is complicated. See this SO post for examples involving sed, perl and awk.

  • I guess to truly answer the original poster you need a slight tweak: (.@.), plus I'm not sure the \..* is good enough in case there are subdomains. – asoundmove Nov 17 '15 at 1:07

Perl to the rescue:

perl -pe '
    sub asteriskify {
        my $s = shift;
        substr $s, 1, -1, "*" x (length($s) - 2);
        return $s
        "<" . asteriskify($1) . "@" . asteriskify($2)
' < input > output

The substr replaces characters in the string from the second one to the last but one by dots, the number of the dots being the length of the string - 2.

The substitution captures the username to $1 and the domain name without the final part to $2, the ?= part just makes sure it's followed by a dot, whatever and > (see Look Around Assertions in perlre).


Since you asked how to do it with awk, I thought I would prove that it was not too hard. So here goes:

echo "John Doe <john.doe@gmail.com> John Doe <johndoe@hotmail.net> Jane Doe <j.doe@outlook.org>" | \
awk \
{print repl($0)}

function repl(s, m)
  if (match(s,"(<.)([^>]*)(.@.)([^>]*)(.\\.[a-z]*>)", m))
    return substr(s, 1, RSTART-1) m[1] \
           gensub(".","*","g",m[2]) m[3] \
           gensub(".","*","g",m[4]) m[5] \
    return s

using sed:

sed 's/.$//' foo.txt | sed 's#\<\(.\).*\(.@.\).*\(\..*\)#\1***\2***\3#'

first sed get rid of the ending >, and 2nd sed will mask the mail address.


  • 1
    You could shorten that to sed 's#\<\(.\).*\(.@.\).*\(\..*\)\>#\1***\2***\3#' foo.txt and save one sed-process. – markgraf Sep 18 at 6:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.