Linux 根据列匹配2个大型csv?

Linux 根据列匹配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

我有两个大型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@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.