파일 목록에서 데이터를 추출하여 csv로 저장하는 쉘 스크립트

파일 목록에서 데이터를 추출하여 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

이 작업을 수행하는 가장 쉬운 방법은 무엇입니까? (앗, grep...)

답변1

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

이 시도,

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


5003700557,YesIntent,2019-01-21T12:23:10.323Z,AFC5EH5PIHHLO4XS7SG
  • ['\"]작은따옴표와 큰따옴표를 모두 구분 기호로 사용하세요.
  • NF>=26행에 26개 이상의 필드가 있는지 확인하기 위한 것입니다.

답변3

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 입력 로그 파일을 나열하는 데 사용됩니다.

관련 정보