昨天我问过这个问题,并得到了非常棒的答案,在这个网站上提问真是一件乐事。
今天我收到了一个稍微不同的问题
说我有csv1
1,2,3,4
5,6,7,8 --
9,10,11,12
13,14,15 --
并且csv2
1,2,3,4,5 --
20,21,22,23,24
24,25,26,27,28
9,10,11,12,30 --
45,46,47,48,60
我怎样才能只打印前 4 个字段只出现在两个文件之一中的行?换句话说,丢弃每个文件中前四个字段也出现在另一个文件中的行中的所有行。
1,2,3,4
9,10,11,12
20,21,22,23,24
24,25,26,27,28
45,46,47,48,60
请注意,--
实际文件中不存在,我添加它们是为了帮助您注意到差异。
到目前为止,我将所有内容加载到 numpy 数组中并比较每个元素,
if a[i] == b[i] and ...
但我想知道是否有更好的方法使用 Linux 工具来实现此目的。
编辑
csv2 中的每一行在 csv1 中都有对应行,并且同一文件中没有重复的行。基本上,我试图从 csv1 中删除 csv2 并输出 csv1 的其余部分。
答案1
以下是一种方法:
$ awk -F, 'NR==FNR{a[$1$2$3$4]++; next}!a[$1$2$3$4]' csv2 csv1
110,12,31,345
1,12,14,55
12,53,22,10
1,12,32,44
解释
-F,
:将字段分隔符设置为 ,。现在,每行的第一个逗号分隔字段将是$1
,第二个$2
,依此类推。NR==FNR
:这是两个 awk 特殊变量。NR 是当前输入行,FNR 是当前文件的行号。只有在读取第一个文件时,这两个值才会相等。NR==FNR{a[$1$2$3$4]++; next}
:在读取第一个文件时,将前 4 个字段保存为数组中的键,a
并将其值设置为 1。这基本上保存了所有前 4 个字段csv1
。next
确保我们立即跳到下一行,而不处理脚本的其余部分。!a[$1$2$3$4]
:awk 的默认操作是打印当前行。因此,如果您使用某个求值为 true 的指令,awk 就会明白它应该打印此行。当未定义!a[ $1$2$3$4]
时为 true ,这种情况将发生在的前 4 个字段不存在于 的任何行中的行。因此,此指令将导致打印所有前 4 个字段从未出现过的行(因此它们在数组中的值不是 1)。a[$1$2$3$4]
csv1
csv2
a