Всем привет. Вчера решал задачу фильтрации txt-файла и нашёл конструкцию на awk, от которой испытал эстетический оргазм. Решил с вами ею поделиться.
Итак, задача: есть data.txt с данными и filter.txt со списком фильтрации.
Строки data.txt обрабатываются, если есть совпадение в filter.txt. Это классическая задача фильтрации (например, обработка белых и чёрных списков).
Итак, сама конструкция:
awk 'NR == FNR { filter[$0] = 1; next } $0 in filter { print $0, "in filter" }' filter.txt data.txt
Обратите внимание: здесь два блока обработки строк, каждый со своим условием
NR == FNR { filter[$0] = 1; next }$0 in filter { print $0, "in filter" }
Обычно выполняются оба блока: сначала первый, потом второй, но здесь это не так. Первый блок только считывает данные filter.txt в массив filter.
Второй обрабатывает только те строки, которые есть в массиве.
NR — встроенная переменная, номер записи ДЛЯ ВСЕХ файлов.FNR — аналогична предыдущей, но начинается с 1 для каждого нового файла.filter[$0] = 1 — сохраняем всю строку первого файла как ключ массива.next — сразу переходит к обработке следующей строки.
Таким образом, связка условия NR == FNR и next будет работать только для первого файла (filter.txt).
Для второго файла условие NR == FNR уже не соблюдается, поэтому первый блок не выполняется, а второй выполняется, если строка данных присутствует в массиве filter.
Ну и пример из реальной жизни — filter.txt:
RU
BY
data.txt
RU 127.0.0.1
BY 127.0.0.2
US 127.0.0.3
KZ 127.0.0.4
awk 'NR == FNR { filter[$1] = 1; next } $1 in filter { print $2, "in filter" }' filter.txt data.txt
127.0.0.1 in filter
127.0.0.2 in filter
Обратите внимание: на выходе только нужные строки и только нужный столбец. Как же это круто!
filter.txt, загруженное в массив filter, должно помещаться в оперативную память. Иначе система может начать активно использовать swap, а процесс — завершиться из-за нехватки памяти.man awk
man comm
man join
Всем работы без багов.
© Tagd








Комментарии