如何通过perl或bash删除重复行?

如何通过perl或bash删除重复行?,perl,bash,Perl,Bash,我有一份清单: asd@domain.com fff@domain.com yyy@domain.com ttt@test.com rrr@test.com fff@test.com yyy@my.com yyy@my.com 如何做到这一点: 如果在整个列表中,我们看到三封或三封以上同一域名的电子邮件-除第一封外,所有重复的邮件都需要删除 Output: asd@domain.com ttt@test.com yyy@my.com yyy@my.com 第一个sed使用制表符将电子邮件分

我有一份清单:

asd@domain.com
fff@domain.com
yyy@domain.com
ttt@test.com
rrr@test.com
fff@test.com
yyy@my.com
yyy@my.com
如何做到这一点:

如果在整个列表中,我们看到三封或三封以上同一域名的电子邮件-除第一封外,所有重复的邮件都需要删除

Output:

asd@domain.com
ttt@test.com
yyy@my.com
yyy@my.com
第一个sed使用制表符将电子邮件分为两个字段(名称+域),以便uniq在删除重复域时跳过第一个字段,最后一个sed删除制表符

#!/usr/bin/env perl

use strict; use warnings;
use Email::Address;

my %data;

while (my $line = <DATA>) {
    my ($addr) = Email::Address->parse($line =~ /^(\S+)/);
    push @{ $data{ $addr->host } }, $addr->original;
}

for my $addrs (values %data) {
    if (@$addrs > 2) {
        print "$addrs->[0]\n";
    }
    else {
        print "$_\n" for @$addrs;
    }
}

__DATA__
asd@domain.com
fff@domain.com
yyy@domain.com
ttt@test.com
rrr@test.com
fff@test.com
yyy@my.com
yyy@my.com
第一个sed使用制表符将电子邮件分为两个字段(名称+域),以便uniq在删除重复域时跳过第一个字段,最后一个sed删除制表符。

#/usr/bin/env perl
#!/usr/bin/env perl

use strict; use warnings;
use Email::Address;

my %data;

while (my $line = <DATA>) {
    my ($addr) = Email::Address->parse($line =~ /^(\S+)/);
    push @{ $data{ $addr->host } }, $addr->original;
}

for my $addrs (values %data) {
    if (@$addrs > 2) {
        print "$addrs->[0]\n";
    }
    else {
        print "$_\n" for @$addrs;
    }
}

__DATA__
asd@domain.com
fff@domain.com
yyy@domain.com
ttt@test.com
rrr@test.com
fff@test.com
yyy@my.com
yyy@my.com
严格使用;使用警告; 使用电子邮件::地址; 我的%数据; while(我的$line=){ 我的($addr)=电子邮件::地址->解析($line=~/^(\S+/); 推送{$data{$addr->host},$addr->original; } 对于我的$addrs(值%data){ 如果(@$addrs>2){ 打印“$addrs->[0]\n”; } 否则{ 为@$addrs打印“$\un”; } } __资料__ asd@domain.com fff@domain.com yyy@domain.com ttt@test.com rrr@test.com fff@test.com yyy@my.com yyy@my.com
#/usr/bin/env perl
严格使用;使用警告;
使用电子邮件::地址;
我的%数据;
while(我的$line=){
我的($addr)=电子邮件::地址->解析($line=~/^(\S+/);
推送{$data{$addr->host},$addr->original;
}
对于我的$addrs(值%data){
如果(@$addrs>2){
打印“$addrs->[0]\n”;
}
否则{
为@$addrs打印“$\un”;
}
}
__资料__
asd@domain.com
fff@domain.com
yyy@domain.com
ttt@test.com
rrr@test.com
fff@test.com
yyy@my.com
yyy@my.com

我不明白为什么示例输出包含
yyy@my.com
两次,但假设这是一个错误

只要不存在尾随空格字符或更复杂形式的电子邮件地址的问题,就可以使用Perl简单地完成这项工作

perl -aF@ -ne 'print unless $seen{$F[1]}++' myfile
输出

asd@domain.com
ttt@test.com
yyy@my.com

我不明白为什么您的示例输出包含
yyy@my.com
两次,但假设这是一个错误

只要不存在尾随空格字符或更复杂形式的电子邮件地址的问题,就可以使用Perl简单地完成这项工作

perl -aF@ -ne 'print unless $seen{$F[1]}++' myfile
输出

asd@domain.com
ttt@test.com
yyy@my.com

这可能适合您:

sed ':a;$!N;s/^\([^@]*@\([^\n]*\)\)\n.*\2/\1/;ta;P;D' file
asd@domain.com
ttt@test.com
yyy@my.com

这可能适合您:

sed ':a;$!N;s/^\([^@]*@\([^\n]*\)\)\n.*\2/\1/;ta;P;D' file
asd@domain.com
ttt@test.com
yyy@my.com

如果您不介意顺序,只需使用排序:

sort -t '@' -u -k 2,2 your_file
如果你不介意点餐,就点吧

gawk '{print NR "@" $0}' your_file | sort -t '@' -u -k 3,3 | sort -t '@' -k 1,1n | cut -d \@ -f 2-

如果您不介意顺序,只需使用排序:

sort -t '@' -u -k 2,2 your_file
如果你不介意点餐,就点吧

gawk '{print NR "@" $0}' your_file | sort -t '@' -u -k 3,3 | sort -t '@' -k 1,1n | cut -d \@ -f 2-