2017-01-24 10 views
1

이것은 stackoverflow에 내 첫 게시물입니다. \ 0/ 항목이 너무 길지 않기를 바랍니다. 저는 수천 개의 로그 파일에서 정기적으로 데이터를 읽고 필터링하고 출력하는 BASH 스크립트를 작성하고 있습니다. 성능이 중요합니다. 그래서 내가 주로 awk 나 sed 대신에 grep을 사용하고 있습니다.Bash 어떻게 효율적으로 grep을 조작 할 수 있습니까? -Pold multiline output?

grep -Poz는 추가 처리와 관련된 패턴을 사용하여 (다중 행) 데이터를 캡처하는 것과 똑같지 만, 예를 들어 XML 파일이나 SQLite3 일괄 처리 데이터와 같은 데이터를 조작하는 데 주저합니다. 추가 분석을위한 쿼리.

#!/bin/bash 
# Regex: 
# (?s) multiline search 
# Capturegroup 1 = date 
# Capturegroup 2 = time 
# Capturegroup 3 = error type (ERROR, WARN or DEBUG) 
# Capturegroup 4 = error details 
# Positive lookahed, until new line (windows/linux) starts with date, OR (if it's the last line matching the pattern, till the end of the last line. 
# 
REGEX_MULTILINE="(?s)([0-9]{4}-[0-9]{2}-[0-9]{2})[[:space:]]([0-9]{2}:[0-9]{2}:[0-9]{2}[,|.][0-9]{3})[[:space:]]+(ERROR|WARN|DEBUG)(.*?)(?=(?:\r\n|[\r\n])[0-9]{4}-[0-9]{2}-[0-9]{2}|\z)" 
LOGFILE="test.log" 

# write to logfile gives exactly the info I want 
write_log(){ 
    echo -n $(grep -Pzo $REGEX_MULTILINE $LOGFILE) > output_grep1.txt 
} 

# I'm stuck in this part to generate, for example, an XML-file 
write_xml(){ 
    local LOGDATE="" 
    local LOGTIME="" 
    local LOGTYPE="" 
    local LOGINFO="" 
    while IFS= read -r LINE ; do 
    #For testing purposes, to see if brackets contain the full string, 
    #or a line of that string 
    printf '%s\n' "[$LINE]" 
    #processing logic here. Didn't get this far yet 
    while [[ $LINE =~ $REGEX_MULTILINE ]] ; do 
     # regex capturegoups 
     LOGDATE=${BASH_REMATCH[1]} 
     LOGTIME=${BASH_REMATCH[2]} 
     LOGTYPE=${BASH_REMATCH[3]} 
     LOGINFO=${BASH_REMATCH[4]} 
     # send vars to function for output 
     # write_xml_function $LOGDATE $LOGTIME $LOGTYPE $LOGINFO 
     # for testing purposes 
     echo -e "log entry:\n\t 1: $LOGDATE \n\t 2: $LOGTIME \n\t 3: $LOGTYPE \n\t 4: $LOGINFO \n" 
     break 
    done 
done < <(grep -Pzo $REGEX_MULTILINE $LOGFILE) 
} 

로그 파일은 다음과 같이 보일 수 있습니다

:

[2017-01-01 13:15:13,932 INFO server.service.ControllerService - Filter:server.service.model.Filters] 
[2017-01-01 15:36:04,914 INFO server.service.ControllerService - Filter:server.service.model.Filters] 
[2017-01-01 15:55:50,279 ERROR server.service.WebClient - server API failed: [(someError.java:12345)] 
{"someId":"etc","otherId":123,"token":{}}] 
[2017-01-01 15:55:50,366 ERROR server.service.controller.Search - Server error for [/service/search/load]: java.lang.NullPointerException stack[etc] 
java.lang.NullPointerException 
    at server.common.stack(SomeApi.java:123) 
    at server.service.trace(SomeService.java:456) 
    at java.lang.Thread.run(Thread.java:789) 
    etc. 
    etc.] 

대신 나는이 얻을 :

2017-01-01 11:09:42,439 INFO server.service.function.property.PropertyService - Props (re)loaded. 
2017-01-01 11:15:46,155 DEBUG server.service.ApiController - api/start called! params: 
${params} 
2017-01-01 13:01:29,675 ERROR server.service.util.base.FtpClient - Error retrieving file. Directory does not exist. 
2017-01-01 13:15:12,803 DEBUG server.service.ApiController - api/start called! params: 
${params} 
2017-01-01 13:15:13,932 INFO server.service.ControllerService - Filter:server.service.model.Filters 
2017-01-01 15:36:04,914 INFO server.service.ControllerService - Filter:server.service.model.Filters 
2017-01-01 15:55:50,279 ERROR server.service.WebClient - server API failed: [(someError.java:12345)] 
{"someId":"etc","otherId":123,"token":{}} 
2017-01-01 15:55:50,366 ERROR server.service.controller.Search - Server error for [/service/search/load]: java.lang.NullPointerException stack[etc] 
java.lang.NullPointerException 
    at server.common.stack(SomeApi.java:123) 
    at server.service.trace(SomeService.java:456) 
    at java.lang.Thread.run(Thread.java:789) 
    etc. 
    etc. 
2017-01-01 16:17:55,175 DEBUG server.config.app - 

STARTING... 


2017-01-01 16:18:00,040 INFO server.common.service.base.property - Props (re)loaded. 
2017-01-01 17:44:43,959 DEBUG server.service.controller - api/start called! params: 
${params} 

나는 그렙 여러 문자열을 읽는 예상 결과는 이것이다

[2017-01-01 13:15:13,932 INFO server.service.ControllerService - Filter:server.service.model.Filters] 
[2017-01-01 15:36:04,914 INFO server.service.ControllerService - Filter:server.service.model.Filters] 
[2017-01-01 15:55:50,279 ERROR server.service.WebClient - server API failed: [(someError.java:12345)] 
{"someId":"etc","otherId":123,"token":{}}] 
[2017-01-01 15:55:50,366 ERROR server.service.controller.Search - Server error for [/service/search/load]: java.lang.NullPointerException stack[etc]] 
[java.lang.NullPointerException] 
[ at server.common.stack(SomeApi.java:123)] 
[ at server.service.trace(SomeService.java:456)] 
[ at java.lang.Thread.run(Thread.java:789)] 
[ etc.] 
[ etc.] 

나는 무엇을 했습니까? 보기? 이 방법으로 할 수 있습니까?

+0

을 사용할 수 있어야합니다. Perl이나 Python과 같은 다른 것을 사용해야 할 것입니다. – Samadi

+3

@Samadi,'-z'와 함께, 그것은 줄 단위가 아닙니다. –

+2

@Asgair as aside - all-caps 변수 이름은 운영 체제 나 쉘에 의미가있는 변수에 사용되도록 POSIX에 의해 지정되는 반면, 하나 이상의 소문자가있는 이름은 응용 프로그램 용으로 예약됩니다. 당신은 후자의 클래스에서 이름을 사용해야합니다. 이후 버전의 쉘에 새로운 모든 대문자가 추가되면, 사용중인 아무 것도 우연히 덮어 쓰지 않게됩니다. –

답변

1

문제는 read 명령에 있습니다. 기본적으로 read은 줄 바꿈까지 읽지 만 null로 구분 된 문자열을 처리하려고합니다.

당신은 할 전체 파일에 줄 단위를 작동 grep``

while IFS= read -r -d '' LINE ; do 
+0

* gumbble * re : [POSIX guidelines] (http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html)와는 반대로 all-caps 변수 이름을 보여줍니다 (일반적인 쉘 변수를 설정 한 이후 같은 이름의 환경 변수를 덮어 씁니다. 하나의 클래스에 대한 이름 지정 규칙은 반드시 둘 다에 적용됩니다). –

+0

동의합니다.하지만 제공된 코드의 변수 이름을 사용하여 질문에 대답하는 것이 가장 좋습니다. –

+1

StackOverflow의 답변은 다른 사람이 볼 수 있고 복사 할 수있는 표준 코드를 제공하기 때문에 (OP 만 질문하는 것이 아닙니다!) 좋은 사례를 보여주는 데 가치가 있습니다. –