将 CSV 数据过滤到多个单独的文件中

将 CSV 数据过滤到多个单独的文件中

我有一个名为的 CSV 文件file1.csv

something;AD;sss;Andorra;nothing;type_1;sss
something222;AD;sss222;Andorra;nothing222;type_2;aaa
thing;NL;thing3;Netherlands;thing;type_2;bb
etc;US;etc;United States;etc;type_2;nothing

我想为每个国家/地区创建单独的文件。我这样制作 grep:

grep -e "\;AD\;.*\;Andorra\;" file1.csv > fileAD.csv
grep -e "\;NL\;.*\;Netherlands\;" file1.csv > fileNL.csv
grep -e "\;US\;.*\;United\sStates\;" file1.csv > fileUS.csv

这可行,但我拥有世界上所有国家/地区,并且我不想为每个国家/地区编写这些行。还有其他解决办法吗?

我还有一个带有type_1和 的专栏type_2。我需要考虑到这一点。创建了每个国家/地区对应的所有文件后,我需要为每个国家/地区创建新文件,type_1并使用type_2.

例如,对于安道尔,我需要文件:

  • fileAD.csv

    something;AD;sss;Andorra;nothing;type_1;sss
    something222;AD;sss222;Andorra;nothing222;type_2;aaa
    
  • fileADtype_1.csv

    something;AD;sss;Andorra;nothing;type_1;sss
    
  • fileADtype_2.csv

    something222;AD;sss222;Andorra;nothing222;type_2;aaa
    

我认为只查找带有缩写的列是可以的,但出于安全原因,我想要两列,一列带有AD全名,另一列带有全名。Andorra

答案1

假设数据是简单的CSV 数据,即没有字段包含嵌入的分隔符或换行符:

awk -F ';' '
    {
        print > "file" $2    ".csv"
        print > "file" $2 $6 ".csv"
    }' file1.csv

这将每行打印两次,一次打印到仅由第二个字段值给出的文件,一次打印到由第二个和第六个字段值的组合给出的文件。根据问题中的文本,每个输出文件名将以字符串为前缀file并以字符串为后缀。.csv

不对文件名中使用的两个字段的值进行验证。

如果要合并第四个字段中的国家名称:

awk -F ';' '
    {
        print > "file_" $2 "-" $4        ".csv"
        print > "file_" $2 "-" $4 "_" $6 ".csv"
    }' file1.csv

对于给定的数据,这将创建以下文件

file_AD-Andorra.csv
file_AD-Andorra_type_1.csv
file_AD-Andorra_type_2.csv
file_NL-Netherlands.csv
file_NL-Netherlands_type_2.csv
file_US-United States.csv
file_US-United States_type_2.csv

上面的代码在使用 GNU 的系统上可以很好地工作awk。其他awk实现可能会遇到同时打开太多文件进行写入的问题。在这样的awk实现中,您必须更聪明,并记住在写入文件后关闭文件。一旦文件关闭,必须记住在>>下次将数据写入文件时打印,否则文件将被截断。

awk -F ';' '
    function do_print(name) {
        if (seen[name] == 1) print >>name  # append to file
        else                 print  >name  # first write, truncate file
        close(name)
        seen[name] = 1
    }
    {
        do_print("file_" $2 "-" $4        ".csv")
        do_print("file_" $2 "-" $4 "_" $6 ".csv")
    }' file1.csv

这也将使代码awk在 OpenBSD 上运行,而您不能print >使用表达式。


额外(只是为了好玩):使awk代码输出一些统计数据:

awk -F ';' '
    function do_print(name) {
        if (seen[name] > 0) print >>name  # append to file
        else                print  >name  # first write, truncate file
        close(name)
        seen[name]++
    }
    {
        do_print("file_" $2 "-" $4        ".csv")
        do_print("file_" $2 "-" $4 "_" $6 ".csv")
    }
    END {
        for (name in seen)
            printf "Wrote %d lines to \"%s\"\n", seen[name], name >"/dev/stderr"
    }' file1.csv

这会在处理结束时将一些统计信息写入错误流。对于给定的数据:

Wrote 1 lines to "file_NL-Netherlands.csv"
Wrote 1 lines to "file_US-United States_type_2.csv"
Wrote 1 lines to "file_AD-Andorra_type_1.csv"
Wrote 2 lines to "file_AD-Andorra.csv"
Wrote 1 lines to "file_NL-Netherlands_type_2.csv"
Wrote 1 lines to "file_US-United States.csv"
Wrote 1 lines to "file_AD-Andorra_type_2.csv"

相关内容