Linux 根据列匹配2个大型csv?
我有两个大型csv,如下所示: csv1.txtLinux 根据列匹配2个大型csv?,linux,perl,sed,awk,Linux,Perl,Sed,Awk,我有两个大型csv,如下所示: csv1.txt ID,Name a0BQ0007OeSDSA,John a0BQ0013OeBMAU,May a0BQ0003OeAASA,Marry a0BQ0032OeBNGG,Peter .... csv2.txt ID,Email a0BQfg343eBMAU,no@email.com a0BQ0033OeAASA,Mar3ry@email.com a0BQ0007OeSDSA,Johsdn@email.com a0BQ0032OeBNGG,Peter
ID,Name
a0BQ0007OeSDSA,John
a0BQ0013OeBMAU,May
a0BQ0003OeAASA,Marry
a0BQ0032OeBNGG,Peter
....
csv2.txt
ID,Email
a0BQfg343eBMAU,no@email.com
a0BQ0033OeAASA,Mar3ry@email.com
a0BQ0007OeSDSA,Johsdn@email.com
a0BQ0032OeBNGG,Peter@email.com
...
输出:我希望将csv2与csv1匹配,并输出具有相同ID的csv2
csv3.txt
John,Johsdn@email.com
Peter,Peter@email.com
谢谢,您可以使用该命令,但由于数据文件不是根据ID列按顺序排序的,因此您还必须使用命令加上Bash加上该命令跳过标题行
join -t, -o1.2,2.2 <(sed 1d csv1.txt | sort) <(sed 1d csv2.txt | sort)
对于给定的输入,这将产生所需的输出。您可以使用该命令,但由于数据文件不是基于ID列的排序顺序,因此还必须使用命令加上Bash加上该命令跳过标题行
join -t, -o1.2,2.2 <(sed 1d csv1.txt | sort) <(sed 1d csv2.txt | sort)
对于给定的输入,这将产生所需的输出。使用awk:
或
使用awk:
或
纯壳
while IFS=, read -r id1 name
do
while IFS=, read -r id2 email
do
if [ "$id1" = "$id2" ]; then
echo "$name,$email"
fi
done < csv2.txt
done < csv1.txt
Name,Email
John,Johsdn@email.com
Peter,Peter@email.com
纯壳
while IFS=, read -r id1 name
do
while IFS=, read -r id2 email
do
if [ "$id1" = "$id2" ]; then
echo "$name,$email"
fi
done < csv2.txt
done < csv1.txt
Name,Email
John,Johsdn@email.com
Peter,Peter@email.com
这是一个Perl解决方案。它首先从csv2.txt读取电子邮件,并将其存储在哈希中,以便快速查找。然后读取csv1.txt,并从哈希中提取每个名称的电子邮件,并打印名称 如果名称的ID在哈希中没有条目,则将忽略名称
use strict;
use warnings;
open my $fh, '<', 'csv2.txt' or die $!;
my %emails;
while (<$fh>) {
chomp;
my ($id, $email) = split /,/;
$emails{$id} = $email;
}
open $fh, '<', 'csv1.txt' or die $!;
while (<$fh>) {
chomp;
my ($id, $name) = split /,/;
next unless exists $emails{$id};
my $email = $emails{$id} or next;
print "$name,$email\n";
}
这是一个Perl解决方案。它首先从csv2.txt读取电子邮件,并将其存储在哈希中,以便快速查找。然后读取csv1.txt,并从哈希中提取每个名称的电子邮件,并打印名称 如果名称的ID在哈希中没有条目,则将忽略名称
use strict;
use warnings;
open my $fh, '<', 'csv2.txt' or die $!;
my %emails;
while (<$fh>) {
chomp;
my ($id, $email) = split /,/;
$emails{$id} = $email;
}
open $fh, '<', 'csv1.txt' or die $!;
while (<$fh>) {
chomp;
my ($id, $name) = split /,/;
next unless exists $emails{$id};
my $email = $emails{$id} or next;
print "$name,$email\n";
}
如果不需要标题,则将NR>1。也就是说,awk'BEGIN{FS=OFS=,}NR==FNR&&NR>1{a[$1]=$2;a&&$1=a[$1]'csv1.txt csv2.txt中的下一个}$1如果您不想要标头,则将NR>1。也就是说,awk'BEGIN{FS=OFS=,}NR==FNR&&NR>1{a[$1]=$2;next}$1在a&&$1=a[$1]'csv1.txt csv2.txtha中,外壳中的On2解决方案我没有得到你的评论,你能解释更多吗?哈,外壳中的On2解决方案我没有得到你的评论,你能解释更多吗?很好的解决方案。我还在学习perl,有一个问题。my$email=$emails{$id}或next;行中的或下一行有什么好处;。如果id不在散列中,我们将跳过该行,不是吗?@jaypal:是的,如果赋值的值为false undef,0,或者执行下一个,跳过打印。如果为true,则将执行print语句。请注意,访问一个不存在的散列元素会返回undf。谢谢,@Borodin现在已经清楚了。我从一个匹配的id中删除了该电子邮件,并理解了您清晰明了的解释。再次感谢+1很好的解决方案。我还在学习perl,有一个问题。my$email=$emails{$id}或next;行中的或下一行有什么好处;。如果id不在散列中,我们将跳过该行,不是吗?@jaypal:是的,如果赋值的值为false undef,0,或者执行下一个,跳过打印。如果为true,则将执行print语句。请注意,访问一个不存在的散列元素会返回undf。谢谢,@Borodin现在已经清楚了。我从一个匹配的id中删除了该电子邮件,并理解了您清晰明了的解释。再次感谢+1.