perl -F, -lane '
exists $h{$F[0]} or $h[$h{$F[0]}=@h]=$_;
$h=$_; /,false$/ or $_=$h for $h[$h{$F[0]}];
END{ print for @h; }
' duplicates.file
Структуры данных:
%h
, чьи ключи являются первыми полями. (AAA, BBB, CCC и т. д. )и соответствующие значения являются числами, указывающими порядок, в котором встречались ключи. Таким образом, например, клавиша AAA => 0, клавиша BBB => 1, клавиша CCC => 2. @h
, элементами которого являются строки, содержащиеся в порядке печати. Таким образом, если в данных найдены и истина, и ложь, то в массив попадет ложное значение. OTW, если есть один тип данных, то он будет присутствовать. Другой способ — использовать GNU sed:
sed -Ee '
G
/^([^,]*),(false|true)\n(.*\n)?\1,\2(\n|$)/ba
/^([^,]*)(,true)\n(.*\n)?\1,false(\n|$)/ba
/^([^,]*)(,false)\n((.*\n)?)\1,true(\n|$)/{
s//\3\1\2\5/;h;ba
}
s/([^\n]*)\n(.*)$/\2\n\1/;s/^\n*//
h;:a;$!d;g
' duplicates.file
FWIW, код, эквивалентный POSIX для приведенного выше кода GNU -sed, указан ниже:
sed -e '
G
/^\([^,]*\),\(false\)\n\(.*\n\)\{0,1\}\1,\2$/ba
/^\([^,]*\),\(false\)\n\(.*\n\)\{0,1\}\1,\2\n/ba
/^\([^,]*\),\(true\)\n\(.*\n\)\{0,1\}\1,\2$/ba
/^\([^,]*\),\(true\)\n\(.*\n\)\{0,1\}\1,\2\n/ba
/^\([^,]*\),true\n\(.*\n\)\{0,1\}\1,false$/ba
/^\([^,]*\),true\n\(.*\n\)\{0,1\}\1,false\n/ba
/^\([^,]*\)\(,false\)\n\(\(.*\n\)\{0,1\}\)\1,true$/{
s//\3\1\2/
h
ba
}
/^\([^,]*\)\(,false\)\n\(\(.*\n\)\{0,1\}\)\1,true\n/{
s//\3\1\2\n/
h
ba
}
y/\n_/_\n/
s/\([^_]*\)_\(.*\)$/\2_\1/;s/^_*//
y/\n_/_\n/
h;:a;$!d;g
' duplicates.file
AA,false
BB,false
CC,false
DD,true
Для этого можно использовать awk
:
Предполагая, что Trn-status
всегда предшествуетTECHNICAL EXCEPTION
awk -F'[\;\=]' '
{ if ( $0 ~ /Trn-status: INCOMPLETE/ ) checkid[$2]=$2 ;
if ( $2 == checkid[$2] ) {
if ( $0 ~ /TECHNICAL EXCEPTION/ ) print checkid[$2]
}
}' logfile
Пояснение:
-F'[\;\=]'
используйте либо ;
, либо =
в качестве разделителей полей; использование квадратных скобок позволяет вам определить несколько разделителей полей, точка с запятой и знак равенства являются специальными символами для awk
, поэтому вам нужно экранировать их обратной косой чертой $0
представляет собой всю строку, ~
представляет собой (подчиненный )оператор сопоставления с образцом и /PATTERN/
строку поиска. Поэтому, если мы находим Trn-status: INCOMPLETE
в строке, мы сохраняем поле ID (номер два, разделенное ;
и =
от других полей )в массиве checkid
, где индекс — это имя Сам ID(awk
позволяет использовать строки в качестве индексных счетчиков)TECHNICAL EXCEPTION
и распечатать идентификатор, если да logfile
имя вашего файла)Эта задача слишком сложна для grep
, но можно использовать sed
, например:
sed '/Trn-status:/h;/\\"message\\":\\"TECHNICAL EXCEPTION\\"/!d;G;/Trn-status: INCOMPLETE/!d;s/.*"errorCode\\":\\"//;s/\\".*//' yourfile
/Trn-status:/h
чтобы всегда сохранять последнюю Trn-status
строку в ячейке хранения /\\"message\\":\\"TECHNICAL EXCEPTION\\"/!d
означает d
удаление всех строк без(!
)заданного шаблона. Обратите внимание, что обратную косую черту необходимо экранировать другой обратной косой чертой TECHNICAL EXCEPTION
сообщений, но теперь нам нужно убедиться, что Trn-status
равно INCOMPLETE
, поэтому мы добавляем пробел с G
и delete
, если мы не не найтиTrn-status: INCOMPLETE
s/.*"errorCode\\":\\"//
)и после(s/\\".*//
)кода, который вы ищете. Бессовестно опираясь на хороший урок @Fiximan по множественным разделителям для awk
.
Предположение о неопределенном содержании данных, поэтому итерация по полям для поиска фактического кода ошибки.
awk -F'[:;,=]' '{
if ( $0 ~ /Trn-status: INCOMPLETE/ ) checkid[$2]=$2 ;
if ( $2 == checkid[$2] && $0 ~ /TECHNICAL EXCEPTION/ ) {
for (i=1; i<=NF; i++) {if ( $i ~ "\"errorCode") print $(i+1), $2
}
}
}' logfile | sed "s/[\\\"]//g"