キー=値ブロックをCSVに変換

キー=値ブロックをCSVに変換

あるファイルの内容を別のファイルに置き換えようとしています。

入力ファイルTest.txt:

HLRSN = 3
IMSI = 404212109727229
KIVALUE = A24AD11812232B47688ADBF15CE05CA9
K4SNO = 1
CARDTYPE = SIM
ALG = COMP128_3

HLRSN = 3
IMSI = 404212109727230
KIVALUE = A24AD11812232B47688ADBF15CE05CB8
K4SNO = 1
CARDTYPE = SIM
ALG = COMP128_3

HLRSN = 3
IMSI = 404212109727231
KIVALUE = A24AD11812232B47688ADBF15CE05CD6
K4SNO = 1
CARDTYPE = SIM
ALG = COMP128_3

他のテキストファイルから希望の出力:

3,404212109727229,A24AD11812232B47688ADBF15CE05CA9,1,SIM,COMP128_3
3,404212109727230,A24AD11812232B47688ADBF15CE05CB8,1,SIM,COMP128_3
3,404212109727231,A24AD11812232B47688ADBF15CE05CD6,1,SIM,COMP128_3

答え1

簡単に:

awk -v RS= -v OFS=, '{print $3,$6,$9,$12,$15,$18}'

記録区切り記号RS=)できるようにする短絡モードここで、レコードは一連の空行に分かれています。レコード内にはデフォルトのフィールド区切り文字が適用されるため(レコードはスペースで区切られています)、各レコードの目的のフィールドは3番目、6番目、9番目です。

私たちは変わる出力フィールド区切り文字はカンマ文字(OFS=,)で、目的のフィールドを印刷します。

答え2

一方bash通行:

declare -a out

EOF=false
IFS=$'='

until $EOF; do
  read -r skip val || EOF=true
  if [ ! -z "$val" ]
  then
    out+=("${val//[[:space:]]/}")
  else
    tmp="${out[@]}"
    printf '%s\n' "${tmp// /,}"
    out=()
  fi
done < file

どのように動作しますか?

  • out出力行を保持する配列を宣言し、EOFファイルの終わりを追跡するように変数を設定し、IFS入力フィールド区切り文字を使用しますread
  • ファイルの終わりを読むまでファイルの各行を読み、最後のフィールドの値を変数に設定しますval
  • if [ ! -z "$val" ]:変数の長さがゼロで$valないことを確認するために、スペースを削除して$val配列にプッシュしますout
  • 長さが$val0の場合、つまり空の行またはファイルの終わりが表示されたら、配列内のすべての要素をout変数tmpに割り当て、すべての空白変数を設計した出力履歴区切り文字tmpに置き換えます。,
  • outさらなる作業のためにnullに設定してください。

もう一つのクリーンで短い解決策は、次のものを使用することですperl

$ perl -F'=' -anle '
    BEGIN { $, = "," }
    push @out,$F[-1] if @F;
    print @{[map {s/\s// && $_} @out]} and @out = ()
        if /^$/ or eof;
' file
3,404212109727229,A24AD11812232B47688ADBF15CE05CA9,1,SIM,COMP128_3
3,404212109727230,A24AD11812232B47688ADBF15CE05CB8,1,SIM,COMP128_3
3,404212109727231,A24AD11812232B47688ADBF15CE05CD6,1,SIM,COMP128_3

答え3

以下をファイルに保存します(例split.awk:)。

BEGIN {
RS="\n\n";
FS="\n";
ORS=",";
}

{
    for (i=1;i<=NF;i++)
    {
        split($i, sf, "= ")
        print sf[2]
    }
    printf "\n"
 }

次に、次を実行します。

awk -f split.awk Test.txt

または、コマンド全体を1行で実行します。

awk 'BEGIN {RS="\n\n";FS="\n";ORS=",";}{for(i=1;i<=NF;i++){split($i, sf, "= ")print sf[2]}printf "\n"}' Test.txt

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

  • ブロックはBEGIN最初に一度実行され、レコード区切り記号(RS)を2つの改行に設定し、フィールド区切り記号(FS)を単一の改行に設定します。出力レコード区切り文字(ORS)はコンマに設定されています。

  • 次に、レコードの各フィールド(NF現在のレコードのフィールド数)を繰り返し、「=」に分割します。

  • ORS次に、各分割の間にコンマ()を使用してその分割の右側を印刷します。

  • 各行の後に改行文字が印刷され、CSV形式を提供します。

答え4

使用ミラーmlr)私たちは、単一の改行で区切られたフィールドを含み、等号で区切られたキーと値のペアを含む二重改行で区切られたレコードでデータを読み取ることができます。余分な空白と空の列(これらの区切り文字を使用してデータを読み取った結果、各フィールド値の先頭にスペースを追加)を削除してからCSVに変換できます。

$ mlr --ips = --ifs lf --irs lflf --ocsv clean-whitespace then remove-empty-columns Test.txt
HLRSN,IMSI,KIVALUE,K4SNO,CARDTYPE,ALG
3,404212109727229,A24AD11812232B47688ADBF15CE05CA9,1,SIM,COMP128_3
3,404212109727230,A24AD11812232B47688ADBF15CE05CB8,1,SIM,COMP128_3
3,404212109727231,A24AD11812232B47688ADBF15CE05CD6,1,SIM,COMP128_3

出力にCSVヘッダーを含めない場合は、このオプションをmlr一緒に使用してください-N。 Millerは、埋め込み区切り文字または引用符を含むすべてのフィールドを自動的に引用します。

関連情報