【问题标题】:Finding Duplicate rows based on a column in Unix File根据 Unix 文件中的列查找重复行
【发布时间】:2021-04-18 08:21:42
【问题描述】:

我有一个包含大约 100 万条记录的文件。我需要为 id 提取具有不同 FName 和 LName 的记录。

输入文件

Col1,Col2,Col3,Col4,ID,FName,Col5,LName,Col6,Col7,Col8
AP,abc@gmail.com,xyz1,abc1,123,Ram,,Kumar,phn1,fax1,url1
AP,abc2@gmail.com,xyz2,abc2,123,Shyam,,Kumar,phn2,fax2,url1
AP,abc@gmail.com,xyz1,abc1,345,Raman,,Kumar,phn2,fax2,url1
AP,abc@gmail.com,xyz1,abc1,345,Raman,,Kumar,phn2,fax2,url1
AP,abc@gmail.com,xyz1,abc1,567,Alex,,Smith,phn2,fax2,url1
AP,abc@gmail.com,xyz1,abc1,789,Allen,,Prack,phn2,fax2,url1

我想看到的结果

AP,abc@gmail.com,xyz1,abc1,123,Ram,,Kumar,phn1,fax1,url1
AP,abc2@gmail.com,xyz2,abc2,123,Shyam,,Kumar,phn2,fax2,url1

任何 AWK 或 Sed 命令或脚本都可以提供帮助吗?谢谢

【问题讨论】:

  • 请在您的问题中以代码的形式添加您的努力,这是非常鼓励的,谢谢。
  • 当然。添加它。
  • 您能否解释一下为什么 567,Alex,Smith 和 789,Allen,Prack 行没有出现在预期的输出中,尽管它们的名字和姓氏是唯一的。
  • 他们在文件中没有重复的 id。
  • 请在您的问题中填写所有信息,不要分散在人们可能会错过的 cmets 中。我以为 abc1 和 abc2 是你的 ID 值。

标签: linux unix awk sed


【解决方案1】:

这个单线应该可以完成这项工作:

awk -F "," '!a[$5] {a[$5]=$0} a[$5]!=$0{print a[$5]; print $0; a[$5]=$0}' input_file.txt

输出:

AP,abc@gmail.com,xyz1,abc1,123,Ram,,Kumar,phn1,fax1,url1
AP,abc2@gmail.com,xyz2,abc2,123,Shyam,,Kumar,phn2,fax2,url1

请注意,整行都是根据 ID 进行比较的。

【讨论】:

    【解决方案2】:
    awk -F, -v id="123" '$1 == id { map[NR]=$0 } END { for(i in map) { print map[i] } }' file
    

    使用 awk,将字段分隔符设置为逗号,并传入一个名为 id 的变量。当第一个字段等于传递的 id 时,添加到一个名为 map 的数组中,以记录号为索引,并以行作为值。最后循环遍历数组并打印值。

    【讨论】:

      【解决方案3】:

      你可以试试这个awk:

      awk 'BEGIN {FS=OFS=","} {id = $5; name = $6 FS $8} id in map && map[id] != name {if (!done[id]++) print rec[id]; print} {map[id] = name; rec[id] = $0}' file
      
      AP,abc@gmail.com,xyz1,abc1,123,Ram,,Kumar,phn1,fax1,url1
      AP,abc2@gmail.com,xyz2,abc2,123,Shyam,,Kumar,phn2,fax2,url1
      

      或者更具可读性:

      awk 'BEGIN {
         FS=OFS=","
      }
      {
         id = $5
         # name variable to store fname, lname
         name = $6 FS $8
      }
      # if this id is already stored as key in map and if it is there check
      # if stored name is different from current name
      id in map && map[id] != name {
         # print previous record if not already printed
         if (!done[id]++)
            print rec[id]
         # print current record
         print
      }
      {
         # store name by key as id in map array
         # and store full record by key as id in rec array
         map[id] = name
         rec[id] = $0
      }' file
      

      【讨论】:

      • 谢谢。您能否解释一下这一步 - $1 in map && map[$1] != name { print $1, map[$1] ORS $0
      • 这对我来说看起来很完美,只需添加 | awk '!seen[$0]++' 即可删除重复项,否则可能会产生很多结果
      • @anubhava 感谢您的回答。实际上,在 id 和 Lname 之前和之后我还有其他字段... WhatIf ID 是文件中的第 5 个字段,FName 是第 6 个,LName 是第 8 个。还有更多字段,我如何打印这些字段并考虑到第 5、第 6 和第 8 位?
      • @RaghavendraGupta,恕我直言,答案将始终仅由显示的示例提供,如果此答案不适用于您的实际文件并且适用于显示的示例,那么您需要提及靠近您的示例实际文件,否则很难帮助/指导这个文件,所以请用适当的细节编辑你的问题,然后让我们,谢谢。
      • @RaghavendraGupta:检查我更新的答案。请预先提供所有相关信息以获得最佳答案,这只是对未来问题的建议。
      【解决方案4】:

      对数组数组使用 GNU awk:

      $ awk -F, '
          { vals[$5][$6 FS $8] = $0 }
          END {
              for ( id in vals ) {
                  if ( length(vals[id]) > 1 ) {
                      for (name in vals[id]) {
                          print vals[id][name]
                      }
                  }
              }
          }
      ' file
      AP,abc@gmail.com,xyz1,abc1,123,Ram,,Kumar,phn1,fax1,url1
      AP,abc2@gmail.com,xyz2,abc2,123,Shyam,,Kumar,phn2,fax2,url1
      

      或者如果您的输入文件按示例输入中所示的“id”排序,则使用任何 awk 并且不将输入文件存储在内存中:

      $ cat tst.awk
      BEGIN { FS=OFS="," }
      NR > 1 {
          id   = $5
          name = $6 FS $8
      
          if ( id == prevId ) {
              if ( name != prevName ) {
                  if ( firstRec != "" ) {
                      print firstRec
                      firstRec = ""
                  }
                  print
              }
          }
          else {
              firstRec = $0
          }
      
          prevId   = id
          prevName = name
      }
      

      $ awk -f tst.awk file
      AP,abc@gmail.com,xyz1,abc1,123,Ram,,Kumar,phn1,fax1,url1
      AP,abc2@gmail.com,xyz2,abc2,123,Shyam,,Kumar,phn2,fax2,url1
      

      【讨论】:

      • 名字和姓氏不同大小写(大小写)被认为是不同的名字。我们可以做些什么来忽略案例?
      • 再次,请不要在 cmets 中展开需求,将其全部放在您的问题中(并在 yoru 示例中包含一个案例来测试它)。话虽如此,只需将name = $6 FS $8 更改为name = tolower($6 FS $8) 使其不区分大小写
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-27
      • 1970-01-01
      • 2013-11-02
      • 2021-07-31
      • 2019-02-09
      • 1970-01-01
      相关资源
      最近更新 更多