【问题标题】:How to group by email in CSV without knowing the email addresses?如何在不知道电子邮件地址的情况下按 CSV 中的电子邮件分组?
【发布时间】:2022-01-14 15:44:48
【问题描述】:

我有一个包含不同列的 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

}

【问题讨论】:

  • 输入是否按电子邮件排序?
  • 不,不是。
  • 您可以使用sort -t$';' -k5 ur_file 按电子邮件地址对文件进行排序。您可以使用sort -t$';' -u -k5 ur_file | cut -d ';' -f 5 获取 uniq 电子邮件地址

标签: bash shell csv grouping


【解决方案1】:

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

awk '
    BEGIN {FS = OFS = ";"}
    {
        if (NR == FNR) {
            str = $2 " " $3 " " $4
            if (arr[$5]) {
                arr[$5] = arr[$5] " && " str
            } else {
                arr[$5] = str
            }
        } else {
            print $0, arr[$5]
        }
    }
' 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

【讨论】:

  • 这非常有效。但它只向我显示终端中的最终 CSV,并没有将字符串添加到文件中。为什么?
  • 好吧,当你有想要的输出 在终端 (就像大多数 unix 命令一样),那么你可以将输出重定向到一个新文件,如下所示:@ 987654323@
【解决方案2】:

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

Awk 有 associatives array(在大多数语言中也称为映射),它可能会帮助您解决问题。

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

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

玩得开心 =)

【讨论】:

    【解决方案3】:

    假设这些行按电子邮件地址分组并且文件没有空行,则此 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-05
      • 2011-12-29
      • 1970-01-01
      • 2010-10-08
      • 2017-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多