【问题标题】:How to delete rows from a csv file based on a list values from another file?如何根据另一个文件中的列表值从 csv 文件中删除行?
【发布时间】:2019-03-10 00:06:08
【问题描述】:

我有两个文件:

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 中运行。

【问题讨论】:

    标签: bash csv awk sed grep


    【解决方案1】:

    你可以同时使用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 sed 中的 -r 相同。

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

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

      • 这里有一种保留标题的方法:{ IFS= read -r header; echo "$header"; join -t, -v1 &lt;(sort) &lt;(sort blacklist.csv); } &lt; candidates.csv
      【解决方案3】:

      下面的呢:

       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 的记录数(即如果我们正在读取第一个文件),则将所有值存储在数组a 中并跳到下一条记录(不要这样做其他)
      • !($1 in a) 如果第一个字段不在数组 a 中,则执行默认操作,即打印该行。这仅适用于第二个文件,因为第一个条件-操作对的条件不成立。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-11
        相关资源
        最近更新 更多