Вопрос или проблема
Мне нужна помощь в реализации команды awk в bash-скрипте для реализации нижеприведенной логики. Пробовал комбинацию sort/uniq, но безуспешно.
У меня есть длинный список с временной меткой и некоторым числом перед ней, как показано ниже.
[2020-09-15 09:03:21.835335] 1021
[2020-09-15 09:03:21.935335] 1021
[2020-09-15 09:03:22.835335] 1022
[2020-09-15 09:03:25.835335] 1022
[2020-09-15 09:04:21.835335] 1023
[2020-09-15 09:05:21.835335] 1023
[2020-09-15 09:04:22.835335] 1023
[2020-09-15 09:05:23.835335] 1023
В конечном итоге я хочу обработать список по отношению ко второму столбцу с числами. В конечных обработанных данных я хотел бы иметь количество уникальных чисел (даже если они встречаются только один раз) из второго столбца и добавить его в новый столбец перед числом. Мне действительно нужно было иметь временную метку с последнего вхождения дубликатов/уникальных записей из столбца с числами.
[2020-09-15 09:03:21.935335] 1021 2
[2020-09-15 09:03:25.835335] 1022 2
[2020-09-15 09:05:23.835335] 1023 4
tac file | uniq -c -f 2 | awk '{$(NF+1)=$1;$1=""}1' | tac
tac
выводит файл в обратном порядке. Это необходимо, чтобы гарантировать, что будет сохранено последнее вхождение дублированных строк.
uniq -c -f 2
сравнивает только последнее поле, пропуская первые два с помощью -f 2
. Оно добавляет количество дублированных строк с флагом -c
, поэтому мы должны перенести это количество в последнее поле. Это делает команда awk '{$(NF+1)=$1;$1=""}1'
.
Наконец, tac
возвращает все в нужном порядке.
[2020-09-15 09:03:21.935335] 1021 2
[2020-09-15 09:03:25.835335] 1022 2
[2020-09-15 09:05:23.835335] 1023 4
$ awk '
{ map[$3]=$1" "$2; cnt[$3]++ }
END { for (key in map) print map[key], key, cnt[key] }
' file
[2020-09-15 09:03:21.935335] 1021 2
[2020-09-15 09:03:25.835335] 1022 2
[2020-09-15 09:05:23.835335] 1023 4
Вышеупомянутое выведет строки в случайном порядке, если нужно сохранить порядок из входных данных, это небольшая настройка, например:
$ awk '
!($3 in map) { keys[++k] = $3 }
{ map[$3]=$1" "$2; cnt[$3]++ }
END { for (i=1;i<=k;i++) {key=keys[i]; print map[key], key, cnt[key]} }
' file
[2020-09-15 09:03:21.935335] 1021 2
[2020-09-15 09:03:25.835335] 1022 2
[2020-09-15 09:05:23.835335] 1023 4
Ответ или решение
Вопрос, заданный в контексте, касается необходимости обработки текстового файла с временными метками и числовыми значениями за помощью инструментов командной строки Linux, таких как awk
, sort
, и uniq
. Основной целью является создание нового файла, в котором каждая уникальная строка по последнему числовому столбцу сопровождается числом повторений этой строки и временной меткой последнего вхождения.
Теория
В Unix-подобных системах и в особенности в Linux, awk
является мощным инструментом для анализа и обработки текстовых данных. Этот инструмент может использоваться для фильтрации текста, сопоставления шаблонов, обработки данных по столбцам и многого другого. Совместно с другими утилитами, такими как sort
и uniq
, можно выполнять сложную обработку данных, прямо в командной строке.
-
tac: Эта команда используется для вывода содержимого файла в обратном порядке. Она полезна, когда необходимо работать с последними вхождениями строк в файле, как в нашем случае.
-
uniq: Эта команда полезна для нахождения и обработки уникальных строк в файле. В контексте текущей задачи
uniq
используется в сочетании с флагом-c
для подсчёта количества повторений, и флагом-f
для игнорирования первых полей при сравнении строк. -
awk: Записи обрабатываются в
awk
с использованием простой, но мощной системы сопоставления шаблонов и действий. Он обрабатывает каждую строку, разделяя её на поля и предоставляя гибкие возможности для манипуляции данными внутри строк.
Пример
Для наглядности рассмотрим пример. У вас есть файл с данными приведенного ниже формата:
[2020-09-15 09:03:21.835335] 1021
[2020-09-15 09:03:21.935335] 1021
[2020-09-15 09:03:22.835335] 1022
[2020-09-15 09:03:25.835335] 1022
[2020-09-15 09:04:21.835335] 1023
[2020-09-15 09:05:21.835335] 1023
[2020-09-15 09:04:22.835335] 1023
[2020-09-15 09:05:23.835335] 1023
Цель: получить файл формата, где каждая уникальная строка идентифицируется по последнему числовому полю, имеет временную метку последнего вхождения и количество повторений:
[2020-09-15 09:03:21.935335] 1021 2
[2020-09-15 09:03:25.835335] 1022 2
[2020-09-15 09:05:23.835335] 1023 4
Применение
Для достижения этой цели можно воспользоваться несколькими подходами. Рассмотрим один из них, использующий awk
в сочетании с tac
и uniq
.
tac file.txt | uniq -c -f 2 | awk '{$(NF+1)=$1;$1=""}1' | tac
-
Использование
tac
для обращения порядка строк в файле. Это позволит нам начать обработку с последнего вхождения каждого числа, чтобы сохранить последнюю временную метку. -
Применение
uniq -c -f 2
: Эта комбинация позволяет игнорировать первые два поля (временная метка) и сосредоточиться только на уникальности числового поля. Флаг-c
добавляет количество повторений каждой строки в начало. -
awk
для пост-обработки:awk '{$(NF+1)=$1;$1=""}1'
перемещает количество повторений из начала строки в конец, оставляя строку с числовым полем и временной меткой. -
Финальное
tac
возвращает строки в их изначальный порядок после обработки.
Альтернативный метод с использованием только awk
:
awk '
{ map[$3]=$1" "$2; cnt[$3]++ }
END { for (key in map) print map[key], key, cnt[key] }
' file.txt
Этот скрипт использует ассоциативные массивы для хранения последней временной метки каждого уникального числа и подсчитывает их количество.
Заключение
Использование утилит командной строки, таких как awk
, uniq
, и tac
, позволяет эффективно обрабатывать текстовые данные без необходимости обращаться к сложным программным языкам. Эти инструменты обеспечивают мощную функциональность и гибкость в манипуляции данными, что делает их незаменимыми для системных администраторов и разработчиков, работающих с большими объемами данных в текстовом формате. Освоение их синтаксиса и возможностей существенно упрощает выполнение рутинных задач по обработке данных в Linux и Unix-системах.