使用grep从文件中删除行,其中键存在于另一个文件中

时间:2012-10-17 14:19:20

标签: bash shell sed awk grep

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

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

然后我想从原始子集中删除所有在delta中存在的字段1中的值的行。

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

我目前正在执行以下操作,但我不明白为什么结果为0。

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

文件: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

文件: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仅存在于子集中,而不是整个文件中的其他位置。

3 个答案:

答案 0 :(得分: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

因此,对于您在subset.csv文件中多次出现1个密钥的情况,您的要求会更好。它假定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

答案 1 :(得分:0)

这应该可以解决问题:

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

答案 2 :(得分:0)

根据您的声明,subset.csv中的所有记录都存在于full.csv中,以下内容应该在bash中有效。它首先使用uniq从full.csv中识别合格的CustomerID。然后,这只是与subset.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)