3

I have a very long list of emails between the < and > characters:

smeimebv2t <jdyefc@nsuwtcvc>; jdedyvt <ejd2ydt2@dv2dg2vgv>; didi2jd2m     <i2dmi32@hd2vdg >; 3idm23i2m <2udhu2@cdrrc>
.
.
.

How can I use an awk or perl one liner in order to capture only the emails addresses between the < >?

example:

more results.out

jdyefc@nsuwtcvc
ejd2ydt2@dv2dg2vgv
i2dmi32@hd2vdg
2udhu2@cdrrc
9

The simplest way I can think of is using GNU grep:

$ grep -Po '<\K[^>]+(?=>)' file 
jdyefc@nsuwtcvc
ejd2ydt2@dv2dg2vgv
i2dmi32@hd2vdg 
2udhu2@cdrrc

The -o means "only print matching region of the line" and the -P activates Perl Compatible Regular Expressions. These let us use \K which means "don't consider anything matched up to this point as part of the match" and positive lookaheads. So, the regex will match an <, then any stretch of non > characters followed by a >.

Note that this will also match <foo> which isn't an email. To restrict to emails only (strings with a @), you can use:

grep -Po '<\K[^>]+@[^>]+(?=>)' file 
4
perl -lne 'print for /<\K[^>]+/g'
4

Using gawk:

awk -v RS="[<>]" '/@/' 
  • 2
    +1 for simplicity, but it's worth mentioning that there better be no other at signs in the input. – ilkkachu Mar 24 '17 at 14:27
1

Another variant:

perl -lne 'print $1 while /<(.*?)>/g'

The parenthesis capture to $1, .*? makes the match non-greedy, i.e. stops as soon as it can.

With awk:

awk -F'<' '{ for(i = 2 ; i <= NF ; i++) { sub(/>.*/, "", $i); print $i; } } ' 

Split the line on <'s, ignore the first part, print others after removing anything starting with >. This will print the the rest of the line if there is no > after a <.

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.