如何在不知道电子邮件地址的情况下按 CSV 电子邮件分组?

How to group by email in CSV without knowing the email addresses?

我有一个包含不同列的 CSV,其中一列包含电子邮件。该脚本应根据列生成一个字符串,并将其作为附加列添加到 CSV 中。目前,脚本遍历每一行并形成字符串。但我想要的是,该脚本只构建具有相同电子邮件地址的行字符串。棘手的是,我不知道不同的电子邮件地址,所以我无法对其进行硬编码并对其进行动态分组。

构建它的方法是什么?

这是我的初始 CSV:

42342;home;2020-01-12;2020-01-13;test@test.com
45235;home;2020-04-12;2020-04-13;test@test.com
68787;photo;2020-05-12;2020-05-13;email@test.com
68787;test;2020-05-12;2020-05-13;moritz@test.com
68787;test;2020-05-12;2020-05-13;moritz@test.com
68787;test;2020-05-12;2020-05-13;moritz@test.com

CSV 最后的样子:

42342;home;2020-01-12;2020-01-13;test@test.com;home 2020-01-12_2020-01-13 && home 2020-04-12_2020-04-13
45235;home;2020-04-12;2020-04-13;test@test.com;home 2020-01-12_2020-01-13 && home 2020-04-12_2020-04-13
68787;photo;2020-05-12;2020-05-13;email@test.com;photo 2020-05-12_2020-05-13
68787;test;2020-05-12;2020-05-13;moritz@test.com;test 2020-05-12_2020-05-13 && test 2020-05-12_2020-05-13 && test 2020-05-12_2020-05-13
68787;test;2020-05-12;2020-05-13;moritz@test.com;test 2020-05-12_2020-05-13 && test 2020-05-12_2020-05-13 && test 2020-05-12_2020-05-13
68787;test;2020-05-12;2020-05-13;moritz@test.com;test 2020-05-12_2020-05-13 && test 2020-05-12_2020-05-13 && test 2020-05-12_2020-05-13

这是我的 bash 脚本:

getPhotosCommand(){
    com=""
    header="ID;DIR;START_DATE;END_DATE" 
    
    while read line; do
        IFS=';' read -r -a array <<< "$line"

        dir=${array[2]}
        start_date=${array[3]}
        end_date=${array[4]}

        newCom="$dir $start_date_$end_date && "
        com=$com$newCom
    
    done < $file_new_photos
    
    echo $com

}

为了解析一个文件并输出另一个 post 处理过的文件,我会使用 awk.

A​​wk 有 associatives array(a.k.a。在大多数语言中都有映射),它可能会帮助您实现这一目标。

简而言之,您的 awk 脚本应该:

  • 在开始块中:初始化关联数组,处理一些参数以在结束块中设置输出。
  • 在您的“行块”中:将当前行插入关联数组,并将电子邮件作为关键字
  • 在你的结束块中:生成循环遍历关联数组的新文件。

玩得开心=)

保留行的原始顺序的两次通过 awk 解决方案。 第一遍用于构建第 6 个字段(针对每封电子邮件),第二遍用于将它们附加到相应的行。

awk '
    BEGIN {FS = OFS = ";"}
    {
        if (NR == FNR) {
            str =  " "  " " 
            if (arr[]) {
                arr[] = arr[] " && " str
            } else {
                arr[] = str
            }
        } else {
            print [=10=], arr[]
        }
    }
' file.scsv file.scsv

输出:

42342;home;2020-01-12;2020-01-13;test@test.com;home 2020-01-12 2020-01-13 && home 2020-04-12 2020-04-13
45235;home;2020-04-12;2020-04-13;test@test.com;home 2020-01-12 2020-01-13 && home 2020-04-12 2020-04-13
68787;photo;2020-05-12;2020-05-13;email@test.com;photo 2020-05-12 2020-05-13
68787;test;2020-05-12;2020-05-13;moritz@test.com;test 2020-05-12 2020-05-13 && test 2020-05-12 2020-05-13 && test 2020-05-12 2020-05-13
68787;test;2020-05-12;2020-05-13;moritz@test.com;test 2020-05-12 2020-05-13 && test 2020-05-12 2020-05-13 && test 2020-05-12 2020-05-13
68787;test;2020-05-12;2020-05-13;moritz@test.com;test 2020-05-12 2020-05-13 && test 2020-05-12 2020-05-13 && test 2020-05-12 2020-05-13

假设这些行按电子邮件地址分组并且文件没有空行,这个 bash 脚本可能就是您要执行的操作。

#!/bin/bash

cnt=0
while IFS= read -r line; do
    email=${line##*;}
    if [ "$email" = "$prev_email" ]; then
        grpline[cnt++]=$line
    else
        if ((cnt)); then
            tail=
            for ((i = 0; i < cnt; ++i)); do
                IFS=';' read -ra fld <<< "${grpline[i]}"
                tail+=" && ${fld[1]} ${fld[2]}_${fld[3]}"
            done
            tail=${tail:4}
            for ((i = 0; i < cnt; ++i)); do
                printf '%s;%s\n' "${grpline[i]}" "$tail"
            done
        fi
        prev_email=$email
        grpline[0]=$line
        cnt=1
    fi
done < <(cat file; echo)

如果文件未按电子邮件地址分组,则将 cat file 替换为 sort -t \; -k5 file