Bash:複数行出力を1行に変換

Bash:複数行出力を1行に変換

私が取得する複数行の出力は次のとおりです。

実際の出力:

GenuineIntel,Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz,CPU0,64,EM64T Family 6 Model 45 Stepping 7,(null),3093,0
GenuineIntel,Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz,CPU1,64,EM64T Family 6 Model 45 Stepping 7,(null),3093,0

#Bashスクリプトでは、上記の出力を1つの記号で区切られた列と2つのカンマで区切られた列の値を持つ行に変換する必要があります。

予想出力:

GenuineIntel#GenuineIntel,Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz#Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz,CPU0#CPU1 and so on.

どうすればいいですか?

答え1

awk以下は、ファイルの特定の内容に依存しない、より一般的なアプローチです。

awk -F, '{for(i=1;i<=NF;i++){a[NR][i]=$(i)}}
         END{
            for(i=1;i<NF;i++){printf "%s#%s,",a[1][i],a[2][i]} 
            print a[1][NF]"#"a[2][NF]
        }' file

説明する

  • for(i=1;i<=NF;i++){a[NR][i]=$(i)}:各行のフィールド(で区切られた-F,)を繰り返して、変数をi1からフィールド数()までのNFすべての値に設定します。NR現在の行番号です。あなたの例では1または2です。a[NR][i]=$(i)行ごとに2D配列を設定し、各フィールドをここに保存します。デフォルトでは、配列は次のaようになります。

      1                        2                        3   
    1 1st field of 1st line    2nd field of 1st line    3rd field of 1st line
    2 1st field of 2nd line    2nd field of 2nd line    3rd field of 2nd line
    

    など。これにより、これがa[1][2]最初の行の2番目のフィールドになります。

  • END{}:ファイルの残りの部分を処理した後にこれを実行します。

  • for(i=1;i<NF;i++){printf "%s#%s,",a[1][i],a[2][i]}:すべてのフィールドを繰り返し、最初の行の現在のフィールド#と2行目の対応するフィールドを印刷します。
  • print a[1][NF]"#"a[2][NF]:最後のフィールドを印刷します(1行ずつ)。これは別々に行われるため、他のものを印刷してその後にカンマを付けることができますが、これの後には改行文字が続きます。

Perlでも同じアイデアが機能します。

perl -F, -ane 'chomp($F[$#F]);
               $k{$.}=\@F; 
               END{
                for($l=0;$l<$#F;$l++){
                  print "${$k{1}}[$l]#${$k{2}}[$l],"
                }
                print "${$k{1}}[$#F]#${$k{2}}[$#F]\n"}' file

これは、ファイル内の特定のテキストに依存しないという利点があります。各行に同じ数のカンマ区切りフィールドがある限り、すべてのデータ行に対して機能します。

答え2

perlゴルフ:

perl -F, -lane'push@{$f[$_]},$F[$_]for 0..$#F}{$,=",";$"="#";print map"@{$_}",@f'

答え3

入力データが次の名前のファイルにある場合input

$ awk -F, '/CPU0/{for (i=1; i<=NF;i++) {a[i]=$i};next} {for(i=1;i<=NF-1;i++){printf a[i]"#"$i","}; print a[NF]"#"$NF}' input
GenuineIntel#GenuineIntel,Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz#Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz,CPU0#CPU1,64#64,EM64T Family 6 Model 45 Stepping 7#EM64T Family 6 Model 45 Stepping 7,(null)#(null),3093#3093,0#0

awk一度に1つのコマンドを実行します。

  • -F,

    これは、awk入力フィールド区切り文字としてコンマを使用することを意味します。

  • /CPU0/{for (i=1; i<=NF;i++) {a[i]=$i};next}

    最初/CPU0/は、最初の行(CPU0の行)を選択するアドレスセレクタです。この行の場合は、すべてのフィールド値を配列に保存しますa。このコマンドは、次の行にジャンプするようにnext指示します。awk

  • for(i=1;i<=NF-1;i++){printf a[i]"#"$i","}

    これは、最初の行の列、ハッシュ記号、2番目の行の列、コンマを順番に印刷することを意味しawkます。すべてのフィールドに対してこれを行い、最後のフィールドを保存します。ii

    printf使用されるため、改行文字は印刷されません。

  • print a[NF]"#"$NF}

    これはawk、最初の行の最後のフィールドを印刷し、その後にポンド表示を指定してから、2行目の最後のフィールドを印刷するように指示します。

    使用されるため、print最後の文字は改行文字で印刷され、出力が完了します。

答え4

$ cat /tmp/tmp     
GenuineIntel,Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz,CPU0,64,EM64T Family 6 Model 45 Stepping 7,(null),3093,0     
GenuineIntel,Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz,CPU1,64,EM64T Family 6 Model 45 Stepping 7,(null),3093,0     
GenuineIntel,Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz,CPU2,64,EM64T Family 6 Model 45 Stepping 7,(null),3093,0    
$ awk -F ',' 'BEGIN{ORS=" ";cpu=",";print "GenuineIntel,"} {gsub(/GenuineIntel/,"");for (i=1;i<=2;i++) {printf $i};print "#";cpu=cpu"#"$3 } END{sub(/,#/,",",cpu);print cpu}' /tmp/tmp
GenuineIntel,  Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz #  Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz #  Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz # ,CPU0#CPU1#CPU2     

完璧ではありません。#最後に1行があります。正面にあるので,CPU0#CPU1#CPU2削除できます。

関連情報