如何根据另一个文件中的列表值从csv文件中删除行?

时间:2018-10-04 14:36:34

标签: bash csv awk sed grep

我有两个文件:

candidates.csv

id,value
1,123
4,1
2,5
50,5

blacklist.csv

1
2
5
3
10

我想从candidates.csv中删除第一行(id)包含在blacklist.csv中的值的所有行。 id始终是数字。在这种情况下,我希望输出看起来像这样:

id,value
4,1
50,5

到目前为止,我用于识别重复行的脚本看起来像这样:

cat candidates.csv | cut -d \, -f 1 | grep -f blacklist.csv -w

这给了我输出

1
2

现在,我不知何故需要将此信息通过管道传送回sed / awk / gawk / ...中,以删除重复项,但我不知道如何做。有什么想法我可以从这里继续吗?还是有更好的解决方案?我唯一的限制是它必须在bash中运行。

3 个答案:

答案 0 :(得分:6)

以下内容如何:

 awk -F, '(NR==FNR){a[$1];next}!($1 in a)' blacklist.csv candidates.csv

这是如何工作的?

awk程序是一系列模式-动作对,写为:

condition { action }
condition { action }
...

其中condition通常是一个表达式,action是一系列命令。在这里,第一个条件操作对为:

  • (NR==FNR){a[$1];next},如果总记录数NR等于文件FNR的记录数(即,如果我们正在读取第一个文件),则将所有值存储在数组{{1}中}并跳至下一条记录(不执行其他任何操作)
  • a如果第一个字段不在数组!($1 in a)中,则执行默认操作,即打印行。由于第一个条件操作对的条件不成立,因此只能在第二个文件上使用。

答案 1 :(得分:1)

如果您不太担心candidates.csv文件中各行的顺序,可以使用以下命令:

join -v 1 -t, <(sort -t, candidates.csv) <(sort blacklist.csv)

-v 1从第一个文件(排序后的candidates.csv)请求所有与第一字段和第二个文件(blacklist.csv)不匹配的行。 -t,只是将逗号设置为分隔符。

如果您担心candidates.csv文件中的标题行,可以在排序或更改顺序之前将其删除。

答案 2 :(得分:0)

您可以同时使用sedgrep来获取输出

$ sed -e 's/[0-9]+/&\,/g' blacklist.csv > filter.csv
$ grep -Fvf filter.csv candidates.csv
id,value
4,1
50,5

sed命令向每个,添加id并输出到filter.csvE用于解释MacOSX / FreeBSD中的正则表达式,与GNU -r中的sed相同。

grep使用选项f在文件之间进行比较,然后使用v删除行。 F用于固定字符串。