Я думаю, что grep
- неправильный инструмент для этой работы, и Awk - лучший выбор (также можно использовать Perl или Python, и, без сомнения, другие языки сценариев).
Похоже, вам нужна первая запись для каждого IP-адреса, то есть поле до первого двоеточия в формате журнала. Это говорит о том, что вам нужно:
awk -F: '!($1 in a) { print; a[$1] = 1 }'
Учитывая входное шоу в вопросе, вывод:
10.20.30.40:/var/contain/name1 3877121024 215982080 3661138944 6% /fofo
10.20.30.50:/var/beta/name2 3877121024 215982080 3661138944 6% /fofo
10.20.30.60:/var/alpha/name2 3877121024 215982080 3661138944 6% /fofo
Не могли бы вы объяснить, что делает команда, пожалуйста?
Awk использует ассоциативные массивы, которые могут принимать строки в качестве индексов. Опция -F:
означает, что Awk разбивает строки на поля в двоеточиях, поэтому $1
- это текст перед первым двоеточием (IP-адресом), а (в этом примере) $2
- это весь текст после первого двоеточия. - пока $0
- это целая строка ввода. Программы Awk представляют собой последовательность пар «образец - действие» (или «выражение» или «условие» плюс «действие»). Действие, если оно указано явно, заключено в фигурные скобки (если не указано, по умолчанию используется print $0
- печатать строку ввода). Если шаблон не указан, он эквивалентен сопоставлению всех строк.
В этой программе условие !($1 in a)
, которое проверяет, отображается ли $1
как индекс в массиве a
; общее выражение оценивается как истинное, если индекс не отображается. Когда условие выполняется, действие выполняется. Он печатает (неявно $0
) и устанавливает a[$1]
в 1
, чтобы в случае повторного появления того же IP-адреса условие оценивалось как ложное, предотвращая повторение IP-адреса.
Если бы вы хотели, чтобы последняя запись вместо первой, вы бы использовали вариант схемы, где каждая строка будет сохранена в правильной записи в массиве: { a[$1] = $0 }
и тогда у вас будет шаблон END
запустить после завершения ввода: END { for (i in a) print a[i] }
. Есть бесконечные вариации на тему.
А если я хочу сделать то же самое, но на основе слова после IP-адреса вместо IP-адреса ( / word / ).
Многое зависит от того, как вы определяете слово (или / word / '). Чтобы облегчить свою жизнь, я планирую рассматривать слово как непрерывный набор непустых символов. Разделитель полей может быть регулярным выражением, поэтому я собираюсь использовать [: ]
для разделения на двоеточия или пробелы; слово после IP-адреса будет $2
. Сценарий почти не меняется:
awk -F '[: ]' '!($2 in a) { print; a[$2] = 1 }'
Поскольку в примерах данных все имена после двоеточия отличаются, все 5 строк появляются в выходных данных. Однако, если вы запускаете сценарий для одного и того же файла несколько раз (добавьте data data
после показанного сценария, где файл data
содержит входные данные вашего примера), и вы получите только одну копию строк в выводе, что обнадеживает .