Вот решение для gawk
(GNU awk
; т.е. версия awk
встречается в большинстве систем «Linux»).
Предположим, что $ cat
настроен на категорию, которую вы хотите найти,
и $ num
установлен на количество записей, которые вы хотите отображать.
awk -vRS='\n[ 0-9][ 0-9][ 0-9][0-9] ' -vcat="$cat" -vnum="$num" \
' BEGIN { first=1; rec_ind=0}
{ if (first) {
rec = $0
first=0
} else {
rec = save_seq $0
}
findnl = index(rec, "\n")
if (findnl < 7) exit
thiscat = substr(rec, findnl-3, 3)
if (cat == thiscat) records[++rec_ind] = rec
if (length(RT) == 0) {
# print "This should be the last record."
save_seq = "Does not matter"
} else if (length(RT) == 6) {
save_seq = substr(RT, 2, 5)
} else {
print "Invalid RT: len =", length(RT)
exit
}
}
END { num_recs = asort(records, sorted_records, "@val_num_desc")
if (num < num_recs) num_recs = num
for (i=1; i<=num_recs; i++) {
print sorted_records[i]
}
}
'
Примечания:
-vRS = '\ n [0-9] [0-9] [0-9] [0-9]'
устанавливает RS
awk (разделитель записей) переменную
в регулярное выражение, состоящее из новой строки,
, за которой следует целочисленный порядковый номер до четырех цифр,
, за которым следует пробел.
Я добавил новую строку, потому что ваши данные имеют четырехзначные числа
(с пробелами) внутри строк,
где они не должны интерпретироваться как разделители записей.
Обратите внимание, что это регулярное выражение немного небрежно, так как оно принимает 007
и 12 4
.
Установка этого параметра в качестве разделителя записей awk означает, что каждая из ваших «транзакций» будет рассматриваться как одна запись awk, даже если она содержит несколько строк. Есть несколько недостатков:
1
в начале ваших данных
не будет распознан как разделитель записей. Мы разберемся с этими проблемами.
-vcat = "$ cat"
и -vnum = "$ num"
аналогичным образом устанавливают переменные awk
cat
и num
к значениям соответствующих переменных оболочки. НАЧАТЬ {первый = 1; rec_ind = 0}
инициализирует флаг first
значением true (1),
, чтобы мы могли распознать первую запись и обработать ее специально,
и индекс записи ( rec_ind
) на 0,
для накопления записей, соответствующих желаемой категории. если (first)
истинно (мы обрабатываем первую запись),
установить rec
равным записи awk, $ 0
.
Помните, что сюда входят все строки до (но не включая)
следующей строки, которая начинается с четырехзначного числа.
Кроме того, он включает четырехзначное число в начале первой строки.
Затем мы устанавливаем флаг первый
в значение false (0).
Если это не первая запись,
тогда отсутствует ее четырехзначный номер
(потому что это разделитель записи ),
поэтому мы создаем запись ( rec
)
путем объединения сохраненного порядкового номера ( save_seq
) с $ 0
.
(Я сейчас расскажу о save_seq
.)
findnl = index (rec, "\ n")
находит первую новую строку в записи
(помните, записи содержат несколько строк).
Если от начала меньше 7 символов,
тогда нет места для порядкового номера и категории
(без перекрытия), не говоря уже о других полях, так что это ошибка.
В противном случае извлеките категорию этой записи ( thiscat
)
из последних трех символов перед первой новой строкой -
т. Е. Последних трех символов строки первая строка сделки.
Затем, если thiscat
соответствует категории, которую мы ищем,
сохраните запись в массиве records
. RT
- признак конца записи -
символы, соответствующие шаблону RS
в конце текущей записи.
К сожалению, ограничитель текущей записи
на самом деле является началом следующей.
Если текущая запись является последней,
тогда RT
будет пустой строкой (длина 0);
в противном случае она всегда должна состоять из 6 символов long (новая строка,
четыре символа, которые являются пробелами или цифрами, и пробел).
Извлеките последние пять символов (т.е. отбросьте новую строку)
и сохраните их как save_seq
,
, потому что это порядковый номер следующей транзакции. num
из них.