使用sed或awk排序和拆分CSV文件

时间:2019-05-12 01:55:16

标签: bash awk sed

我有一个如下所示的CSV文件(test.csv):

WH_01,TRAINAMS,A10,1221-ESD
WH_03,TRAINLON,L10A3,3005-21
WH_01,TRAINAMS,A101,PWR-120
WH_02,TRAINCLE,A1,074-HD-SATA
WH_01,TRAINAMS,A10,PWR-120
WH_02,TRAINCLE,A15,102-55665
WH_03,TRAINLON,L10A3,3005-20
WH_03,TRAINLON,UK-B3,101859

1)。我可以根据第2列中的值对文件进行排序,如下所示:

sort -t, -k2,2 test.csv > testsort.csv

2)。接下来,我想根据第2列中的值拆分文件。使用上面的示例,它应该创建3个文件:

testsort_1.csv:
WH_01,TRAINAMS,A10,1221-ESD
WH_01,TRAINAMS,A101,PWR-120
WH_01,TRAINAMS,A10,PWR-120

testsort_2.csv:
WH_02,TRAINCLE,A1,074-HD-SATA
WH_02,TRAINCLE,A15,102-55665

testsort_3.csv:
WH_03,TRAINLON,L10A3,3005-20
WH_03,TRAINLON,L10A3,3005-21
WH_03,TRAINLON,UK-B3,101859

我该怎么做?不知道是否需要排序,是否可以不进行排序即可达到以上目的。

谢谢。

3 个答案:

答案 0 :(得分:2)

分开sortawk的好举动。

$ sort -t, -k2,2 test.csv |awk -F, '!($2 in T) {T[$2]=++i} {print > ("testsort_" i ".csv")}'

$ tail -n +1 testsort*
==> testsort_1.csv <==
WH_01,TRAINAMS,A10,1221-ESD
WH_01,TRAINAMS,A101,PWR-120
WH_01,TRAINAMS,A10,PWR-120

==> testsort_2.csv <==
WH_02,TRAINCLE,A1,074-HD-SATA
WH_02,TRAINCLE,A15,102-55665

==> testsort_3.csv <==
WH_03,TRAINLON,L10A3,3005-20
WH_03,TRAINLON,L10A3,3005-21
WH_03,TRAINLON,UK-B3,101859
  • !($2 in T)-如果在数组T的索引中找不到第二个字段,
  • {T[$2]=++i}-递增计数器并将第二个字段保存为索引。
  • {print}-打印每一行
  • > "file"-覆盖,重定向并将输出附加到文件
  • ("." i ".")-连接“字符串”和变量

答案 1 :(得分:2)

由于您不确定是否需要排序几乎肯定意味着您不需要,并且您只是出于某种原因认为它很有用,而且您只是按$ 2排序,然后根据$ 2的价值,因此排序毫无用处。

您真正需要做的是:

O(n)

看:

awk -F, '{print > ($2".csv")}'

如果过去大约20个输出文件名并且未使用GNU awk,则每当$ 2更改时,您都必须关闭每个文件,并使用$ ls test.csv $ awk -F, '{print > ($2".csv")}' test.csv $ ls test.csv TRAINAMS.csv TRAINCLE.csv TRAINLON.csv $ tail -n +1 TRAIN* ==> TRAINAMS.csv <== WH_01,TRAINAMS,A10,1221-ESD WH_01,TRAINAMS,A101,PWR-120 WH_01,TRAINAMS,A10,PWR-120 ==> TRAINCLE.csv <== WH_02,TRAINCLE,A1,074-HD-SATA WH_02,TRAINCLE,A15,102-55665 ==> TRAINLON.csv <== WH_03,TRAINLON,L10A3,3005-21 WH_03,TRAINLON,L10A3,3005-20 WH_03,TRAINLON,UK-B3,101859 而不是>>附加到他们。

如果出于某些原因您确实确实需要使用问题中的输出文件名,则为:

>

答案 2 :(得分:0)

您可以通过保持文件名计数器并使用sprintf为每个连续文件组创建文件名,以相当简单的方式进行操作。您使用FNR(文件记录号)来区分第一条记录和后续记录。

例如:

$ sort -t, -k2 file.csv | 
awk -F, -v cnt=1 -v fn="testsort_1.csv" '
    FNR==1 {
        prev=$2
        print $0 > fn
    } 
    FNR>1 {
        if ($2!=prev) {
            cnt++
            fn=sprintf("%s_%d.csv", "testsort", cnt)
        }
        print $0 > fn
        prev=$2
    }'

注意:您将初始文件名设置为开始的变量,然后使用cntsprintf(计数)创建所有后续文件名。{{1 }}跟踪上一条记录的第二个字段。prevfn和计数器创建的文件名。)

最初将sprintf声明为变量的同一脚本的简短版本为:

prev

如果您不希望使用顺序编号的文件,而是希望从已排序的记录中提取sort -t, -k2 file.csv | awk -F, -v cnt=0 -v prev="" '{ if ($2!=prev) { cnt++ fn = "testsort_" cnt ".csv" prev=$2 } print $0 > fn }' ,请查看@Cyrus现已删除的答案,该答案提供了一种出色(更短)的解决方案那方面。 (我看到您已经有了很好的答案)

使用/输出示例

使用您在"testsort_number.csv"中的输入,将创建以下输出文件:

file.csv