0

我有一个 csv 文件,我将使用它作为输入,格式如下:

xValue,value1-avg,value1-median,value2-avg,value3-avg,value3-median
1,3,4,20,14,20

输入文件的关键属性是每个“值”都会有可变数量的统计信息,但统计信息类型和“值”总是用“-”分隔。然后我想将所有“值”的统计信息输出到单独的 csv 文件中。

输出将如下所示:

值1.csv

xvalue,value1-avg,value1-中位数
1,3,4

值2.csv

xvalue,value2-avg
1,20

我已经尝试找到解决方案,但我能找到的只是按列号复制的方法,而不是标题名称。我需要能够使用标题名称将关联的统计信息附加到每个输出 csv 文件。

任何帮助是极大的赞赏!

PS 在此脚本的先前运行期间可能已写入输出文件,这意味着代码应附加到输出文件

4

3 回答 3

2

未经测试但应该接近:

awk -F, '
NR==1 {
    for (i=2;i<=NF;i++) {
        outfile = $i
        sub(/-.*/,".csv",outfile)
        outfiles[i] = outfile
    }
}
{
    delete(outstr)
    for (i=2;i<=NF;i++) {
        outfile = outfiles[i]
        outstr[outfile] = outstr[outfile] FS $i
    }
    for (outfile in outstr)
        print $1 outstr[outfile] >> outfile
}
' inFile.csv

请注意,删除整个数组delete(outstr)是 gawk 特定的。使用其他 awk,您可以使用它split("",outstr)来获得相同的效果。

请注意,这会将您想要的输出附加到现有文件中,但这意味着您将在每次执行时重复标题行。如果这是一个问题,请告诉我们如何知道何时生成标题行,但我认为您想要的解决方案如下所示:

awk -F, '
NR==1 {
    for (i=2;i<=NF;i++) {
        outfile = $i
        sub(/-.*/,".csv",outfile)
        outfiles[i] = outfile
    }
    for (outfile in outfiles) {
        exists[outfile] = ( ((getline tmp < outfile) > 0) && (tmp != "") )
        close(outfile)
    }
}
{
    delete(outstr)
    for (i=2;i<=NF;i++) {
        outfile = outfiles[i]
        outstr[outfile] = outstr[outfile] FS $i
    }
    for (outfile in outstr)
        if ( (NR > 1) || !exists[outfile] )
            print $1 outstr[outfile] >> outfile
}
' inFile.csv
于 2013-09-04T15:22:18.110 回答
0

只需找出与每列关联的名称并使用该映射来操作列。如果您尝试在 awk 中执行此操作,则可以使用关联数组来存储列名和对应的行。如果您使用的是 ksh93 或 bash,则可以使用关联数组来存储列名和对应的行。如果你使用 perl 或 python 或 ruby​​ 或......你可以......

或者将列推入数组以将数字映射到列号。

无论哪种方式,您都有一个列标题列表,可以根据需要进一步操作。

于 2013-09-04T03:37:36.230 回答
0

我发现对这类问题最有用的解决方案是首先使用 AWK 脚本(封装在 shell 函数中)检索列号,然后使用 cut 语句。这种技术/策略变成了一种非常简洁、通用和快速的解决方案,可以利用协同处理。非附加情况更清晰,但这是一个处理您提到的附加复杂性的示例:

#! /bin/sh
fields() {
        LC_ALL=C awk -F, -v pattern="$1" '{
                j=0; split("", f)
                for (i=1; i<=NF; i++) if ($(i) ~ pattern) f[j++] = i
                if (j) {
                        printf("%s", f[0])
                        for (i=1; i<j; i++) printf(",%s", f[i])
                }
                exit 0
        }' "$2"
}
cut_fields_with_append() {
        if [ -s "$3" ]
        then
                cut -d, -f `fields "$1" "$2"` "$2" | sed '1 d' >> "$3"
        else
                cut -d, -f `fields "$1" "$2"` "$2" > "$3"
        fi
}
cut_fields_with_append '^[^-]+$|1-' values.csv value1.csv &
cut_fields_with_append '^[^-]+$|2-' values.csv value2.csv &
cut_fields_with_append '^[^-]+$|3-' values.csv value3.csv &
wait

结果如你所料:

$ ls
values  values.csv
$ cat values.csv 
xValue,value1-avg,value1-median,value2-avg,value3-avg,value3-median
1,3,4,20,14,20
$ ./values
$ ls
value1.csv  value2.csv  value3.csv values  values.csv
$ cat value1.csv
xValue,value1-avg,value1-median
1,3,4
$ cat value2.csv
xValue,value2-avg
1,20
$ cat value3.csv 
xValue,value3-avg,value3-median
1,14,20
$ ./values
$ cat value1.csv 
xValue,value1-avg,value1-median
1,3,4
1,3,4
$ cat value2.csv 
xValue,value2-avg
1,20
1,20
$ cat value3.csv 
xValue,value3-avg,value3-median
1,14,20
1,14,20
$
于 2015-10-23T02:42:07.470 回答