将 csv 文件与查找列 1 进行比较,然后检查第 2 列中的值

将 csv 文件与查找列 1 进行比较,然后检查第 2 列中的值

好的,我会尽力解释我需要做什么。基本上我有两个 CSV 文件,如下例所示:

文件一:

Column 1, Column 2
abc     , 123
def     , 234
adf     , 567

文件2

Column 1, Column 2
abc     , 123
def     , 234
adf     , 578

我需要编写一个 shell 脚本或简单命令来执行以下操作:

  1. 按第 1 列对两个文件进行排序
  2. 逐行执行以下操作:
    • 使用文件 1 中的第 1 列,在文件 2 的第 1 列中搜索该值。
      1. 如果找到,则将文件 1 第 2 列中的值与文件 2 第 2 列中的值进行比较
      2. 如果匹配,则将第 1 列、第 2 列和第 3 列中的“已验证”写入单独的文件
      3. 如果不匹配,则将第 1 列、第 2 列和“失败”写入单独的文件

这会产生两个输出文件:第一个包含在第 1 列和第 2 列中找到的所有内容匹配,第二个文件包含失败的第 1 列查找或找到第 1 列但第 2 列不匹配的位置,因此,本质上,使用第 1 列作为检查第 2 列的键。

答案1

给定以下输入文件:

$ cat in1 in2
Column 1, Column 2
abc     , 123
def     , 234
adf     , 567
Column 1, Column 2
abc     , 123
def     , 234
adf     , 578

首先,我们对它们进行排序;然后我们可以将它们拼接成一个文件:

$ sort in1 > in1.sorted; sort in2 > in2.sorted; paste in{1,2}.sorted
Column 1, Column 2  Column 1, Column 2
abc     , 123   abc     , 123
adf     , 567   adf     , 578
def     , 234   def     , 234

awk在这里会帮助我们,但是逗号会妨碍我们;我们可以首先摆脱它们sed

$ paste in{1,2}.sorted | sed s/,//g
Column 1 Column 2   Column 1 Column 2
abc      123    abc      123
adf      567    adf      578
def      234    def      234

然后我们可以通过快速转储它awk

$ paste in{1,2}.sorted | sed s/,//g | awk '$2 == $4 {print $1,"Validated"}; $2 != $4 { print $1,"Failed"}'
Column Failed
abc Validated
adf Failed
def Validated

这也可以使用 raw 来完成awk,优点是能够去掉标题行,并且不依赖于相同顺序的相同数据,从而消除了排序的需要:

$ awk 'FNR != 1 && NR == FNR {data[$1]=$3} FNR != 1 && NR != FNR {if(data[$1]==$3) {print $1, "Validated"} else {print $1, "Failed"} }' in{1,2}
abc Validated
adf Failed
def Validated

这依赖于一些神奇的awk内置变量和与之相关的技巧:

  • NR- 处理的记录总数
  • FNR- 记录总数在当前文件中处理
  • FNR != 1- 跳过每个文件的第一行(不将标题视为数据)
  • NR != FNR- 仅在第一个文件完全读取并且我们已开始读取后续文件后运行。这允许我们data在开始咀嚼第二个文件后预先填充数组以进行测试。

答案2

我想我现在已经通过以下内容解决了这个问题,以防其他人读到这个并需要这个。再次感谢。

FNR == NR {
    for (i = 2; i <= NF; i++) { a[i,$1] = $i }
    b[$1];
    next;
}
($1 in b) {                   # check if row in file2 existed in file1
    for (i = 2; i <= NF; i++) {
        if (a[i,$1] == $i)
            printf("%s->col%d: %s vs %s: Valid\n", $1, i-1, a[i,$1], $i);
        else
            printf("%s->col%d: %s vs %s: Failure\n", $1, i-1, a[i,$1], $i);
    }
    delete b[$1];   # delete entries which are processed
}

END {
    for (left in b) {   # look which didn't match
        for (i = 2; i <= NF; i++) 
            printf("%s->col%d: %s vs (blank): Not Equal\n", left, i-1, a[i,left])
    }
}

答案3

使用(以前称为 Perl_6)

#! /usr/bin/env raku
    
    #INPUT AND HEADERS:

    my $csv1 = "Veyron1.txt".IO;
    my $csv2 = "Veyron2.txt".IO;

    my $hdr1 = "Key,Value,Verified";
    my $hdr2 = "Key,Value,Failed";

    #HASH STORAGE (Below, beware of `skip`ping header in headerless file!):

    my %csv1; for $csv1.lines.skip.map( *.split(",").map( *.trim)) {
                  %csv1.push: .[0] => .[1]
              };
    my %csv2; for $csv2.lines.skip.map( *.split(",").map( *.trim)) {
                  %csv2.push: .[0] => .[1]
              };

    #SANITY CHECKS:

    die "multiple values per key in file_1" if any(%csv1.values.map: *.elems > 1).so; 
    die "multiple values per key in file_2" if any(%csv2.values.map: *.elems > 1).so;

    #OUTPUT FILE PREP W/ HEADER:

    !("Veyron_output_verified.txt".IO.e) && (my $fh1 = "Veyron_output_verified.txt".IO.open: :a); 
    !("Veyron_output_failed.txt".IO.e) && (my $fh2 = "Veyron_output_failed.txt".IO.open: :a); 

    $fh1.put: $hdr1;
    $fh2.put: $hdr2;

    #OUTPUT LOOP:

    for %csv1.keys.sort -> $id {
       if  %csv2{$id}:exists {
           if  %csv1{$id}  eq  %csv2{$id} {
               $fh1.put: ($id, %csv1{$id}, "verified").join: ",";
           }
           else {
               $fh2.put: ($id, %csv1{$id}, "mismatch").join: ",";
           }
       }
       else {
          $fh2.put: ($id, %csv1{$id}, "absent").join: ",";
       }
    }

    $fh1.close;
    $fh2.close;

这是用 Raku(Perl 系列编程语言)编写的脚本。与 Perl 一样,Raku 具有键/值数据结构以及各种文件操作符,这使得它非常适合解决此类性质的问题。简要地:

  • 顶部的$-sigiled$csv1表示$csv2文件句柄(实际上是.IO对象)。因为符号在 Raku 中保持不变......
  • 两个%签名哈希值%csv1%csv2分别表示从每个文件获取的键/值的存储位置。
  • 修剪空白、标头操作和健全性检查为运行代码增加了细节。
  • 文件运算符(.e例如“exists”)可确保预先存在的输出文件不会被覆盖。文件句柄用:a选项打开,代表:append.
  • 在输出循环中,%csv1在 , 中查找键来%csv2检查字符串等价(与eq) 同源values.返回三个字符串之一:“已验证”、“不匹配”或“不存在”。
  • 输出按行附加到打开的输出文件句柄,该句柄在脚本末尾关闭。

注意:如果您想检查数值等价每个键的值,替换:

%csv1{$id} eq %csv2{$id}和: %csv1{$id} == %csv2{$id}


示例输出(“已验证”):

Key,Value,Verified
abc,123,verified
def,234,verified

示例输出(“失败”):

Key,Value,Failed
adf,567,mismatch

乐库参考资料:
https://docs.raku.org
https://raku.org

相关 Perl 脚本:
https://www.perlmonks.org/?node_id=805106

相关内容