複数行のレコードを「値」部分のみを含む単一のCSV行に折りたたみます。

複数行のレコードを「値」部分のみを含む単一のCSV行に折りたたみます。

以下のように複数行の記録されたデータがあります。

Name>Ami  
Admin>2  
Oper>1  
Name>Sum  
Admin>3  
Total>2  
Name>Tar  
Admin>1  
Oper>2

Name今、これらのレコードをレコード要素とAdmin「値」部分のみを含む単一のCSV行に縮小しようとしていますOper。この例では、最終出力は次のようになります。

Ami,2,1  
Sum,3,
Tar,1,2  

出力は得られますが、その値を一致させて最初と2番目の列に入れてから3番目の列に入れたいpaste - - - -d,ので、使用したくありません。NameAdminOper

ベストアンサー1

あなたが望むようです

  • 複数のレコード行を単一のCSV行に縮小します。
  • レコード属性の値のみを印刷しますNameAdminOper
  • これらの属性のいずれかが提供されていない「明示的な」空のフィールドを印刷します。

私は次のawkプログラムをお勧めします:

awk -F'>' 'function printrec(){printf "%s,%s,%s\n",buf["Name"],buf["Admin"],buf["Oper"]}
           (FNR>1 && $1=="Name"){printrec();delete buf}
           {sub(/[[:space:]]*$/,"",$2); buf[$1]=$2}
           END{printrec()}' input.txt

仕組みは次のとおりです。

  • 入力ファイルのフィールド区切り記号はに設定されます>

  • レコードのすべての要素は連想配列に格納されますbuf

  • printrec()関連フィールドをカンマで区切って印刷する関数が定義されます。特定のキーが含まれていないbuf場合、buf参照は空の文字列として評価され、不足している属性の空のフィールドの要件を満たします。

  • レコードがlineで始まるとしますName。このような行に出会えばいいえファイルの最初の行(FNR>1)は、以前にバッファーされたレコードを印刷し、バッファーを再び消去します。

  • buf各行に対して、現在の属性は「配列インデックス」として「キー」部分を、配列値として「値」部分を使用して保存されます。

    ノートsub()入力例に含まれる「値」部分から末尾のスペースを削除する呼び出しを含めました。実際に空白がないと確信していれば、3行の該当部分は省略してもよい。

  • ファイルの最後に、最後にバッファリングされたレコードが印刷されます。

この手順を例に適用すると、次の結果が表示されます。

Ami,2,1
Sum,3,
Tar,1,2

ノートdelete配列を使用するにはGNUが必要ですawk。味が変わったらawkぜひお試しください

split("",buf)

回避策として。

また、レコードに属性の複数のインスタンスが含まれている場合(Name常にレコードの先頭と見なされない限り)、後続の発生は以前の発生を上書きします。

おすすめ記事