Shell脚本:将csv文件中的标题列复制到另一个csv文件

时间:2013-09-04 00:36:03

标签: shell csv io awk

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

  

x值,值1-AVG,VALUE1中值1,值2-AVG,值3-AVG,值3的中值
  1,3,4,20,14,20

输入文件的关键属性是每个“值”将具有可变数量的统计信息,但统计类型和“值”将始终用“ - ”分隔。然后我想输出所有“值”的统计信息以分离csv文件。

输出看起来像这样:

value1.csv

  

x值,值1-AVG,值1的中值
  1,3,4

value2.csv

  

x值1,值2,平均
  1,20

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

非常感谢任何帮助!

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

3 个答案:

答案 0 :(得分: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的。使用其他awks,您可以使用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

答案 1 :(得分:0)

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

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

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

答案 2 :(得分: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
$