#linux #awk #sed #grep
#linux #awk #sed #grep
Вопрос:
У меня очень большой текстовый файл, который в основном представляет собой журнал сообщений с {
разделителем между сообщениями. Я хочу удалить блоки между {
, если они соответствуют определенному условию. В приведенном ниже примере я хочу удалить средний блок сообщений, который имеет EVENT_TYPE = BDE
, и оставить два ABC
сообщения. Файл находится в ящике Linux, поэтому у меня есть доступ ко всем вашим обычным grep
, sed
, awk
и т. Д. Я могу использовать эти процессы, чтобы найти EVENT_TYPE
, но не уверен, как затем найти больший блок и удалить его.
}
/type/ - DataEvents = {
VALUE = 2342
EVENT_TYPE = ABC
VALUE_YESTERDAY = 1299
HAS_DELAY = false
SEND_TIME_RT = 18:55:21.224 00:00
}
/type/ - DataEvents = {
VALUE = 889
EVENT_TYPE = BDE
VALUE_YESTERDAY = 778
HAS_DELAY = false
SEND_TIME_RT = 18:55:21.224 00:00
}
/type/ - DataEvents = {
VALUE = 123
EVENT_TYPE = ABC
VALUE_YESTERDAY = 345
HAS_DELAY = false
SEND_TIME_RT = 18:55:21.224 00:00
}
Комментарии:
1. Должен ли быть инициал
}
в верхней части образца? Если все эти блоки разделены хотя бы одной пустой строкой (до и после), это становится намного проще.2. этого может быть достаточно:
awk 'BEGIN{RS=ORS="}"} !/EVENT_TYPE = BDE/ amp;amp; NF' file
Ответ №1:
Всякий раз, когда входные данные имеют пары имя = значение, я считаю наиболее удобным / надежным / поддерживаемым / расширяемым сначала создать массив ( f[]
ниже) этого сопоставления для каждой записи ( rec
ниже), а затем получить доступ к значениям по их именам для тестирования, печати и т.д.:
$ cat tst.awk
BEGIN { FS=" *= *" }
NF { rec = rec $0 ORS; f[$1] = $2 }
/^}/ {
if ( f["EVENT_TYPE"] != "BDE" ) {
print rec
}
rec = ""
delete f
}
$ awk -f tst.awk file
/type/ - DataEvents = {
VALUE = 2342
EVENT_TYPE = ABC
VALUE_YESTERDAY = 1299
HAS_DELAY = false
SEND_TIME_RT = 18:55:21.224 00:00
}
/type/ - DataEvents = {
VALUE = 123
EVENT_TYPE = ABC
VALUE_YESTERDAY = 345
HAS_DELAY = false
SEND_TIME_RT = 18:55:21.224 00:00
}
Ответ №2:
Используя gawk для многосимвольных RS, вы можете настроить RS так, чтобы каждый блок обрабатывался как отдельная запись, а затем просто тестировался внутри записи, как обычно. Мы используем NR > 1
, чтобы игнорировать нежелательную первую (пустую) запись, которая возникает из данных, начинающихся с разделителя записей (предполагая, что это так, это неясно из вашего частичного примера).
$ gawk -v RS='/type/' 'NR > 1 amp;amp; !/EVENT_TYPE = BDE/ { printf "/type/%s", $0 }' file
/type/ - DataEvents = {
VALUE = 2342
EVENT_TYPE = ABC
VALUE_YESTERDAY = 1299
HAS_DELAY = false
SEND_TIME_RT = 18:55:21.224 00:00
}
/type/ - DataEvents = {
VALUE = 123
EVENT_TYPE = ABC
VALUE_YESTERDAY = 345
HAS_DELAY = false
SEND_TIME_RT = 18:55:21.224 00:00
}
Ответ №3:
Не могли бы вы попробовать следующее.
awk '
/{/{
val=""
}
/}/{
if(found=="" amp;amp; val){
print val ORS $0
}
found=val=""
next
}
/EVENT_TYPE = BDE/{
found=1
}
{
val=(val?val ORS:"")$0
}
END{
if(val amp;amp; found==""){
print val ORS $0
}
}
' Input_file
Ответ №4:
Как насчет
$ vim -es ' g/EVENT_TYPE = BDE/exe "norm! dap"' ' %print' ' q!' file
Вывод:
}
/type/ - DataEvents = {
VALUE = 2342
EVENT_TYPE = ABC
VALUE_YESTERDAY = 1299
HAS_DELAY = false
SEND_TIME_RT = 18:55:21.224 00:00
}
/type/ - DataEvents = {
VALUE = 123
EVENT_TYPE = ABC
VALUE_YESTERDAY = 345
HAS_DELAY = false
SEND_TIME_RT = 18:55:21.224 00:00
}
Ответ №5:
если ваши данные в ‘d’ по gnu sed
sed -Ez 's/{[^{}]*EVENT_TYPEs*=s*BDE[^}]*}//' d
Ответ №6:
Это может сработать для вас (GNU sed):
sed '/{/{:a;N;/}/!ba;/EVENT_TYPE = BDE/d}' file
Соберите строки между {
и }
и, если эти строки содержат EVENT_TYPE = BDE
, удалите их.