Это мое первое сообщение о stackoverflow. \ 0/ Надеюсь, это не слишком длинная запись. Я пишу сценарий BASH для регулярного чтения, фильтрации и вывода данных из тысяч лог-файлов. Производительность важна, поэтому я использую grep вместо awk или sed.Bash Как эффективно манипулировать многострочным выходом grep -Poz?
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 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}
В результате я ожидаю, при чтении строки Grep многострочный это:
[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 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.]
Что я переделал смотреть? Это можно сделать так?
'grep' работает линия за линией, а не целые файлы. Вам нужно будет использовать что-то еще, например Perl или Python. – Samadi
@ Самади, с '-z', это не строка-лайн. –
@Asgair, как имена переменных в стороне - все-шапки, заданы POSIX для использования в переменных, имеющих значение для операционной системы или оболочки, тогда как имена с хотя бы одним строчным символом зарезервированы для использования приложения; вы должны использовать имена в последнем классе. Если в будущей версии вашей оболочки добавится новый встроенный шаблон, это гарантирует, что вы ничего не используете, чтобы перезаписать его случайно. –