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-median
1,3,4

value2.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 固有であることに注意してください。他の 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
于 2013-09-04T15:22:18.110 に答える
0

この種の問題に対して私が最も役立つ解決策は、最初に AWK スクリプト (シェル関数にカプセル化されている) を使用して列番号を取得し、次に 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 に答える
0

各列に関連付けられた名前を見つけて、そのマッピングを使用して列を操作するだけです。awk でこれを行おうとしている場合は、連想配列を使用して、列名とそれに対応する行を格納できます。ksh93 または bash を使用している場合は、連想配列を使用して、列名と対応する行を格納できます。perl、python、ruby、または ... を使用している場合は...

または、列を配列にプッシュして、数値を列番号にマップします。

いずれにせよ、必要に応じてさらに操作できる列ヘッダーのリストが得られます。

于 2013-09-04T03:37:36.230 に答える