【问题标题】:How to use bash/miller to add a +/- diff column to identify CSV file differences?如何使用 bash/miller 添加 +/- diff 列来识别 CSV 文件差异?
【发布时间】:2018-12-26 16:09:52
【问题描述】:

我有一些数据文件,我想为其生成一个“差异”列,这意味着添加一个列来指示是否从当前文件中添加/删除了特定行。比如我有以下两个文件,a.csv

id,data,data2
1,A,B
2,A,B
3,A,B
4,A,B

b.csv:

id,data,data2
2,A,C
3,A,C
4,A,C
5,A,C

我只想根据id 比较是否添加/删除了一行。数据无所谓。到目前为止,我想出的最好方法是以以下方式使用miller

#!/bin/bash

t1=$(mktemp)
t2=$(mktemp)
t3=$(mktemp)

mlr --icsv --ocsv put '$diff = "-"' then reorder -f diff a.csv > "$t1"
mlr --icsv --ocsv put '$diff = "+"' then reorder -f diff b.csv > "$t2"
mlr --icsv --ocsv join -f "$t1" -j id --ul --ur --np then unsparsify "$t2" > "$t3"
mlr --icsv --ocsv join -f "$t3" -j id --ul --ur      then unsparsify then reorder -f diff,id then sort -nf id b.csv

rm "$t1"
rm "$t2"
rm "$t3"

这会生成以下内容,这就是我想要的:

diff,id,data,data2
-,1,A,B
,2,A,C
,3,A,C
,4,A,C
+,5,A,C

这个解决方案的不幸之处在于它需要运行 miller 四次并使用三个临时文件。 Miller 似乎不适用于 bash 进程替换(<() 业务)。

有没有更直接的方法来生成这种输出?

【问题讨论】:

  • 您可以在每个文件上cut -f1 -d',',然后通过管道传送到diff
  • @jeremysprofile 谢谢,但我最终不会得到需要进一步处理的 CSV 输出文件。
  • join 获取单个文件中的所有数据,awk 进行比较并写入所需的格式?
  • @Poshi 这将导致更少的调用,但它基本上会导致我编写一个程序来执行它,然后我可以用任何语言执行它。我一直在寻找一种可以轻松完成的工具。
  • 你是对的。但是,当代码如此简单且工具不存在时,使用可用的东西可能是矫枉过正,就像这种情况一样。实际上,通过使用 miller,您也是在自己编写程序:您是在告诉 miller 执行大量有序操作。

标签: bash csv miller


【解决方案1】:

有一个专门的工具:https://github.com/paulfitz/daff

如果你在示例中运行 daff a.csv b.csv 你会得到

---,1 ,A ,B → ,2 ,A ,B→C → ,3 ,A ,B→C → ,4 ,A ,B→C +++,5 ,A ,C

【讨论】:

    【解决方案2】:

    以下输出与您发布的完全相同:

    join -t, -11 -22 <(
            # the order of files here is important
            # filter out duplicates too
            sort -t, -u -k1,1 b.csv a.csv
        ) <(
            comm --output-delimiter=, <(
                    <a.csv \
                    cut -d, -f1 |
                    sort
                ) <(
                    <b.csv \
                    cut -d, -f1 |
                    sort
                ) | 
            # this is stupid, but needs to be done anyway
            sed '
                s/^,,/,/;t;
                s/^,/+,/;t;
                s/^/-,/
            '
        ) |
    awk -vFS=, -vOFS=, '{print $4,$1,$2,$3}'
    

    但我们可以使用join -o auto 和简单的awk 来缩短时间:

    join -t, -11 -21  -a1 -a2 -o auto a.csv b.csv | 
    awk -vFS=, -vOFS=, '{
        $6=""
        if (length($2) == 0) { $6="+"; $2=$4; $3=$5; }
        else if (length($4) == 0) { $6="-"; }
        else { $2=$4; $3=$5; }
        print $6,$1,$2,$3
    }'
    

    我有一种奇怪的感觉,我会保留两个文件中的 data2 列,因为它们不同,并且真正简化了思考,只需:

    join -t, -11 -21  -a1 -a2 -o auto a.csv b.csv | 
    awk -vFS=, -vOFS=, '{
        $6=""
        if (length($2) == 0) $6="+"
        if (length($4) == 0) $6="-"
        print $6,$1,$2,$3,$4,$5
    }'
    

    输出:

    -,1,A,B,,
    ,2,A,B,A,C
    ,3,A,B,A,C
    ,4,A,B,A,C
    +,5,,,A,C
    

    解释为:

    # diff, id, data from a.csv, data2 from a.csv, data from b.csv, data2 from b.csv
    

    tutorialspoint 提供实时版本。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-04
      • 1970-01-01
      • 2017-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-19
      相关资源
      最近更新 更多