ファイル変換

ファイル変換

2つの列で構成されるファイルがあります。

A,val1
A,val2
A,val3
B,val1
B,val2
B,val3

私にとって必要なのは、最初の列のすべての固有値に対して、2番目の列が水平になるように出力を変換できることです。

A,val1,val2,val3
B,val1,val2,val3

BASHやAWKを使用するのが最善の方法かどうかはわかりません。両方を組み合わせたものかもしれません。誰でも正しい方向を教えてください。

答え1

awkのみを使用:

$ awk -F, 'BEGIN{OFS=FS} {a[$1] = a[$1] == "" ? $2 : a[$1] FS $2} END {for(i in a) print i,a[i]}' file
A,val1,val2,val3
B,val1,val2,val3

出力順序は保証されません。 GNU awkで修正するのは簡単ですが、他の実装ではより難しいです。入力データをソートする必要はありません。

それ以外の場合は、GNU datamashを使用してください。

datamash -t, groupby 1 collapse 2 < file

(入力が揃っていない場合は追加-s)またはMillerを使用して

mlr --nidx --fs ',' nest --implode --values --across-records --nested-fs ',' -f 2 file

または、よりコンパクトで更新されたバージョン

mlr --nidx --fs ',' nest --ivar ',' -f 2 file

答え2

シェルスクリプトを使用してこの問題を解決する方法はいくつかありますが、私はあまり標準的ではないツールを使用することを好みます。ミラーapt install millerUbuntu / Debianにインストールできます。私はMillerの動詞がbashやawkよりもこの種の問題を考えるためのより自然なツールだと思います。

質問で指定されたデータが次の場所に保存されている場合INPUT_FILE

A,val1
A,val2
A,val3
B,val1
B,val2
B,val3

次はミラーのものですnest動詞複数のレコード(行)をフィールド2に複数の値を持つ単一のレコードにまとめ、フィールド2を複数のフィールドに拡張するために使用できます。

mlr --ocsv --headerless-csv-output \
  nest --implode --values --across-records -f 2 then \
  nest --explode --values --across-fields -f 2 INPUT_FILE

これにより、所望の出力が生成される。

A,val1,val2,val3
B,val1,val2,val3

Millerにはこれを行うより簡単な方法がありますが、これが私が見つけた最初の解決策です。

答え3

出力順序を保証するには、次の awk コードを使用します。ここでは、連想配列とも呼ばれるハッシュ(see [...])を維持します。このハッシュは、新しいキー($ 1)が見つかるたびに増加するカウンターによって入力されます。

$ awk -F "," '
    prev != $1 { prev = $1 }
    !($1 in a) { seen[++n] = $1 }
    { a[$1] = a[$1] FS $2 }
    END {
      for (i=1; i<=n; i++) {
        print seen[i] a[seen[i]] 
      }
    }
  ' file
A,val1,val2,val3
B,val1,val2,val3

答え4

すべてのUnixシステムのすべてのシェルでawkを使用し、一度に1つの$ 1キーブロックのみをメモリに保存しながら、出力ラインの順序を維持します。

$ awk '
    BEGIN { FS=OFS="," }
    $1!=p { printf "%s%s", rec, sep; rec=p=$1; sep=ORS }
    { rec = rec OFS $2 }
    END { print rec }
' file
A,val1,val2,val3
B,val1,val2,val3

関連情報