【问题标题】:Using grep to remove lines from a file, where the keys exist in another file使用 grep 从文件中删除行,其中键存在于另一个文件中
【发布时间】:2012-10-07 20:04:53
【问题描述】:

我正在处理 2 个大型 CSV 文件。较小的是较大的子集。第一个字段是非唯一键,即 customerID。

我想从较大的文件中找到与较小文件在字段 1 中具有相同值的所有行,然后找到该结果与原始子集之间的差异。

然后我想从原始子集中删除所有在增量中存在的字段一中具有值的行。

换句话说:我想从原始较小的子集中删除任何行,该子集中的客户ID 也存在于大原始文件中存在的行中,但不存在于较小的子集中。

我目前正在这样做,我不明白为什么结果是0。

我的逻辑显然存在缺陷,这显然不是最优雅的方法,所以,我愿意接受更好的方法的建议。

文件:完整的.csv

,1052,tec101,UNIX
,1052,ser303,UNIX
,1052,backu2,UNIX
,1052,sma114,UNIX
,1052,appsup,UNIX
,1052,emails,UNIX
,1059,marygs,UNIX
,39835,deepr2,UNIX
,44536,hai499,UNIX
,1274,lemo27,Windows
,48567,wdanro,UNIX
,81860,pro846,UNIX
,1419,graphe,UNIX
,83999,doerf1,UNIX
,1551,taxtri,UNIX
,1572,lodes4,UNIX
,1603,wes244,Windows
,102888,law642,UNIX
,1700,au2960,UNIX

文件:subset.csv

,1052,sma114,UNIX
,1052,appsup,UNIX
,1052,emails,UNIX
,1059,marygs,UNIX
,39835,deepr2,UNIX
,44536,hai499,UNIX
,1274,lemo27,Windows
,48567,wdanro,UNIX
,81860,pro846,UNIX
,1419,graphe,UNIX

我现在在做什么:

[jgalley@linux1 sandbox]$ wc -l *
 19 full.csv
 10 subset.csv
 29 total
[jgalley@linux1 sandbox]$ cat subset.csv |  awk -F, '{print ","$2","}' > subset_keys
[jgalley@linux1 sandbox]$ grep -F -f subset_keys full.csv | wc -l
13
[jgalley@linux1 sandbox]$ grep -F -f subset_keys full.csv | head -n2
,1052,tec101,UNIX
,1052,ser303,UNIX
[jgalley@linux1 sandbox]$ grep -F -f subset_keys full.csv > subset_keys_grep
[jgalley@linux1 sandbox]$ cat subset_keys_grep | awk -F, '{print ","$2","}' | head -n2
,1052,
,1052,
[jgalley@linux1 sandbox]$ cat subset_keys_grep | awk -F, '{print ","$2","}' | wc -l
13
[jgalley@linux1 sandbox]$ cat subset_keys_grep | awk -F, '{print ","$2","}' > keys_to_remove
[jgalley@linux1 sandbox]$ grep -F -f keys_to_remove subset.csv | wc -l
10
[jgalley@linux1 sandbox]$ grep -F -f keys_to_remove subset.csv > lines_to_remove
[jgalley@linux1 sandbox]$ grep -Fv -f lines_to_remove  subset.csv | wc -l
0

我的预期结果应该是 7,或者,如果没有计数,则如下:

,1059,marygs,UNIX
,39835,deepr2,UNIX
,44536,hai499,UNIX
,1274,lemo27,Windows
,48567,wdanro,UNIX
,81860,pro846,UNIX
,1419,graphe,UNIX

结果应该是子集的 7 行,其 customerID 仅存在于子集中,而不存在于完整文件的其他位置。

【问题讨论】:

  • 我不太明白你想要做什么。添加一个具体的缩短示例可能会有所帮助,例如有问题的两个文件,但短的 10 行,长的 20 行。然后指出您希望这些文件如何与您提议的过程和结果相对应。
  • 好的,我会试着想出一个更简单的例子,实际文件中包含敏感信息,所以我不能只提供一个子集来玩。
  • 为什么在结果中排​​除“,1052,sma114,UNIX”、“,1052,appsup,UNIX”, ...?
  • 因为键:1052,在主文件中有记录在子集中不存在但是,1059应该在结果中,所以我编辑了这个。跨度>
  • 但是 ",1419,graphe,UNIX" 在full.csv 也有记录。为什么这个包含在结果中?

标签: bash shell sed awk grep


【解决方案1】:

试试这个。我修改了您的输入“full.csv”以删除前 3 行:

$ cat full1.csv
,1052,sma114,UNIX
,1052,appsup,UNIX
,1052,emails,UNIX
,1059,marygs,UNIX
,39835,deepr2,UNIX
,44536,hai499,UNIX
,1274,lemo27,Windows
,48567,wdanro,UNIX
,81860,pro846,UNIX
,1419,graphe,UNIX
,83999,doerf1,UNIX
,1551,taxtri,UNIX
,1572,lodes4,UNIX
,1603,wes244,Windows
,102888,law642,UNIX
,1700,au2960,UNIX

因此,对于 1 个密钥在您的子集.csv 文件中多次出现的情况,您的要求会更好一些。它假定subset.csv 文件中的行顺序与full.csv 文件中的顺序相匹配。如果不是这种情况,只需进行调整即可拆分字符串...

$ cat test.awk                       
BEGIN{ FS="," }
NR==FNR { key2full[$2] = key2full[$2] $0 ORS; next }
{ key2subset[$2] = key2subset[$2] $0 ORS }
END {
   for (key in key2subset) {
      if (key2subset[key] == key2full[key]) {
         printf "%s", key2subset[key]
      }
   }
}
$ awk -f test.awk full1.csv subset.csv
,1052,sma114,UNIX
,1052,appsup,UNIX
,1052,emails,UNIX
,1419,graphe,UNIX
,44536,hai499,UNIX
,48567,wdanro,UNIX
,1274,lemo27,Windows
,81860,pro846,UNIX
,39835,deepr2,UNIX
,1059,marygs,UNIX

在上面修改过的输入文件上运行我的命令似乎引起了一些混乱。这里是原始文件,所以这里是针对原始文件运行以显示它确实产生了所需的输出:

$ cat full.csv 
,1052,tec101,UNIX
,1052,ser303,UNIX
,1052,backu2,UNIX
,1052,sma114,UNIX
,1052,appsup,UNIX
,1052,emails,UNIX
,1059,marygs,UNIX
,39835,deepr2,UNIX
,44536,hai499,UNIX
,1274,lemo27,Windows
,48567,wdanro,UNIX
,81860,pro846,UNIX
,1419,graphe,UNIX
,83999,doerf1,UNIX
,1551,taxtri,UNIX
,1572,lodes4,UNIX
,1603,wes244,Windows
,102888,law642,UNIX
,1700,au2960,UNIX

$ awk -f test.awk full.csv subset.csv
,1419,graphe,UNIX
,44536,hai499,UNIX
,48567,wdanro,UNIX
,1274,lemo27,Windows
,81860,pro846,UNIX
,39835,deepr2,UNIX
,1059,marygs,UNIX

【讨论】:

  • 我想找到子集的行,这些行具有在完整文件 OTHER 中存在 ELSEWHERE 的键,然后是子集。然后我想从子集中排除这些行。
  • 谢谢您,很抱歉造成混乱。
  • 我想你可能误解了,因为你从这个脚本得到的结果不是想要的结果,应该从结果中删除键为 1052 的行,而不是保留。您之前的单行解决方案实际上工作正常。
  • 我认为您错过了我在答案顶部的注释,即我修改了 OPs 输入(因此输出与最初期望的不同)以突出一个意味着我以前的解决方案不起作用的要求。
  • 但是从输入中删除前几行并不意味着需求更加突出,这意味着需求为零。实际要求与任何密钥在任何文件中出现的次数无关。
【解决方案2】:

这应该可以解决问题:

grep -v -f subset.csv full.csv | awk -F, '{print ","$2",";}' >keys.csv
grep -v -f keys.csv subset.csv

【讨论】:

    【解决方案3】:

    根据您的声明,subset.csv 中的所有记录都存在于 full.csv 中,以下应该在 bash 中工作。它首先使用 uniq 从 full.csv 中识别合格的 CustomerID。然后,这只是与子集.csv 进行连接以进行过滤。

    join -o 2.1,2.2,2.3,2.4 -v 2 -t, -1 2 -2 2 <(sort full.csv subset.csv | uniq -u | 
    sort -k2,2 -t,) <(sort -k2,2 -t, subset.csv)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-14
      • 1970-01-01
      • 2021-09-18
      • 2012-07-07
      相关资源
      最近更新 更多