web-dev-qa-db-ja.com

ファイルのリストからデータを抽出してcsvとして保存するシェルスクリプト

私はCentOSを使用しています。読み取り、ファイルからデータを抽出し、csvファイルとして整理するファイルのリストがあります。

ログファイルのテキスト形式は次のとおりです。

...
{"name":"test-api","hostname":"ci47","pid":3202,"level":30,"msg":"File: dsiManager, Method: getContract, End { userId: 'AFC5EH5PIHHLO4XS7SG',\n  clientId: '5003700557',\n  intent: 'YesIntent',\n }","time":"2019-01-21T12:23:10.323Z","v":0}
...

出力形式は次のとおりでなければなりません:

clientId;intent;time;userId
5003700557;YesIntent;2019-01-21T12:23:10.323Z;AFC5EH5PIHHLO4XS7SG

このタスクを実行する最も簡単な方法は何ですか? (awk、grep ...)

4
tamerbak

Awkコマンドを使用しました。私の問題は、すべての行が他の行とは異なることでした。したがって、列番号についてはわかりませんでした。これを解決するには、表示する正しい行番号を見つけるテストを追加しました。これが私のコードです:

awk ' 
BEGIN {
  # Set awk script delimiter
  FS=","; 
  # Set CSV file separator
  OFS=";"; 
  # Set header part in csv file
  print "Method; UserId; ClientId; intent; time"
  } 
  /'clientId'/ 
  { 
    i=1; 
    msg=""; 
    while(i<=NF) { 
      if ($i ~ /clientId/) { 
        # Cleaning column value :
        gsub(/\\n\s{1,}clientId:\s/, "",$i); 
        msg = msg $i ";"
      };  
      if ($i ~ /"time"/) { 
        # Cleaning column value :
        gsub(/"time":/, "",$i); 
        msg = msg $i ";"
      }; 
      if ($i ~ /intent/) { 
        # Cleaning column value :
        gsub(/\\n\s{1,}intent:\s{1,}/, "",$i); 
        msg = msg $i ";"
      }; 
      if ($i ~ /Method/) { 
        # Cleaning column value :
        gsub(/(^(.*?)|\s{1,})Method\s{1,}?:?\s{1,}/, "",$i); 
        gsub (/(\s{1,}\{\s{1,}userId.*)?/, "", $i);  
        msg = msg $i ";"
      }; 
      if ($i ~ /userId/) { 
        # Cleaning column value :
        gsub(/(^(.*?)|\s{1,})userId:\s/, "",$i); 
        msg = msg $i ";"
      }; 
      i++
    } print msg
  } 
END {
  print NR
} ' 

$(grep -l id *.log) >> output.csv
  1. 古いログファイルがダーティだったので、gsub()メソッドを使用してソンム列の値をクリーンアップしました
  2. $(grep -l id * .log)コマンドは、すべてのawk入力ログファイルを一覧表示するために使用されます
0
tamerbak

JSONでエンコードされたデータを確実に解析するには、JSONコーデックが必要です。これは、PerlまたはPython(またはRuby ...)を意味します。)私はPerlの人なので、ここにPerlソリューションがあります。

まず、ワンライナーから:

$ Perl -MJSON -ne 'BEGIN { print("clientId;intent;time;userId\n"); } eval { my $obj = from_json($_); my $msg = $obj->{msg}; $msg =~ s/^.*{\s*|\s*,\s*}.*$//g; my %m = map { m/^([^:]*):\s*(.*)/; ($1, $2) } split(/,\s+/, $msg); print("$m{clientId};$m{intent};$obj->{time};$m{userId}\n"); }; warn($@) if ($@);' <x
clientId;intent;time;userId
5003700557;YesIntent;2019-01-21T12:23:10.323Z;AFC5EH5PIHHLO4XS7SG

これはPerlでも少し過剰なので、ここにも読みやすいスクリプトがあります。

#!/usr/bin/Perl

use strict;
use warnings;
use JSON;

print("clientId;intent;time;userId\n");
while (<>) {
    # Don't choke on malformed lines
    eval {
        my $obj = from_json($_);
        my $msg = $obj->{msg};
        $msg =~
            s/^.*{\s*    # Trim up to and including the leading '{'
            |
            \s*,\s*}.*$  # Trim trailing ',}'
            //gx;
        # Split $msg into key-value pairs
        my %m = map {
            m/^([^:]*)   # Stuff that isn't ':'
            :\s*         # Field separator
            (.*)         # Everything after the separator
            /x;
            ($1, $2)
        } split(/,\s+/, $msg);
        print("$m{clientId};$m{intent};$obj->{time};$m{userId}\n");
    };
    warn($@) if ($@);
}
2
Chris Williams

これを試して、

awk -F "['\"]" 'NF>=26{print $19","$21","$26","$17}' file.csv


5003700557,YesIntent,2019-01-21T12:23:10.323Z,AFC5EH5PIHHLO4XS7SG
  • ['\"]区切り文字として一重引用符と二重引用符の両方を使用します。
  • NF>=26行が26以上のフィールドを持っていることを確認するだけです。
1
Siva