Пытаюсь разобрать вывод команды “lastb” с помощью awk, но когда поле userID пустое, мои переменные сбиваются.

Вопрос или проблема

Я пытаюсь извлечь дату и IP-адрес из вывода lastb

Я использую: lastb | awk '{print $5,$6,$7,$3}'

Проблема в том, что иногда первый столбец (userID) в lastb пустой:

Пример данных:

wpsadmin ssh:notty    213.109.202.127  Tue Oct  1 12:07 - 12:07  (00:00)
         ssh:notty    8.219.222.66     Tue Oct  1 11:48 - 11:48  (00:00)
quser    ssh:notty    213.109.202.127  Tue Oct  1 11:03 - 11:03  (00:00)
udatabas ssh:notty    139.19.117.130   Tue Oct  1 10:34 - 10:34  (00:00)
Admin    ssh:notty    213.109.202.127  Tue Oct  1 09:58 - 09:58  (00:00)
         ssh:notty    79.110.62.93     Tue Oct  1 09:40 - 09:40  (00:00)
udatabas ssh:notty    139.19.117.130   Tue Oct  1 09:34 - 09:34  (00:00)

…что смещает мои переменные awk на одну позицию.

Поэтому использование: lastb | awk '{print $5,$6,$7,$3}' для приведенного набора данных дает мне:

Oct 1 12:07 213.109.202.127
1 11:48 - Tue
Oct 1 11:03 213.109.202.127
Oct 1 10:34 139.19.117.130
Oct 1 09:58 213.109.202.127
1 09:40 - Tue
Oct 1 09:34 139.19.117.130

Как мне это исправить? Спасибо!

Чтобы смоделировать вызов lastb OP:

$ cat lastb.out
wpsadmin ssh:notty    213.109.202.127  Tue Oct  1 12:07 - 12:07  (00:00)
         ssh:notty    8.219.222.66     Tue Oct  1 11:48 - 11:48  (00:00)
quser    ssh:notty    213.109.202.127  Tue Oct  1 11:03 - 11:03  (00:00)
udatabas ssh:notty    139.19.117.130   Tue Oct  1 10:34 - 10:34  (00:00)
Admin    ssh:notty    213.109.202.127  Tue Oct  1 09:58 - 09:58  (00:00)
         ssh:notty    79.110.62.93     Tue Oct  1 09:40 - 09:40  (00:00)
udatabas ssh:notty    139.19.117.130   Tue Oct  1 09:34 - 09:34  (00:00)

Один общий подход:

  • нам нужно определить, следует ли распечатать поля 5,6,7,3 или поля 4,5,6,2
  • 5,6,7,3 то же самое, что и (5-0),(6-0),(7-0),(3-0)
  • 4,5,6,2 то же самое, что и (5-1),(6-1),(7-1),(3-1)
  • мы можем обобщить это на (5-offset),(6-offset),(7-offset),(3-offset), где offset равно 0 или 1
  • мы можем проверить атрибуты первого поля, чтобы определить значение offset

Несколько идей awk на основе различных атрибутов первого поля:

########
# определяем смещение по содержимому первого поля

awk '
{ offset = ( $1 ~ /ssh:/ ) ? 1 : 0                       # если первое поле содержит строку "ssh:", то смещение = 1, иначе смещение = 0
  print $(5-offset),$(6-offset),$(7-offset),$(3-offset)  # применяем смещение, чтобы определить, какие поля печатать
}'

########
# определяем смещение по позиции первого поля в строке

awk '
{ offset = ( index($0,$1) != 1 ) ? 1 : 0                 # если первое поле не начинается с первого столбца, то смещение = 1, иначе смещение = 0
  print $(5-offset),$(6-offset),$(7-offset),$(3-offset)
}'

Другой подход – это вставить ‘заменяющее’ поле в начало строки, когда первое поле ‘отсутствует’.

Одна идея awk, использующая атрибут index($0,$1):

awk '
{ $1 = (index($0,$1)==1 ? "" : "placeholder" FS) $1    # если первое поле начинается с первого столбца, то заменяющее не нужно, иначе добавляем перед первым полем строку "placeholder"
  $0=$0                                                # заставляем awk повторно разобрать новую строку; поскольку теперь у всех строк одинаковое количество полей ...
  print $5,$6,$7,$3                                    # не нужно смещение
}'

Удалив комментарии, сведя к однострочным выражениям и считывая вывод lastb из stdin:

cat lastb.out | awk '{offset = ($1~/ssh:/) ? 1 : 0; print $(5-offset),$(6-offset),$(7-offset),$(3-offset)}'

cat lastb.out | awk '{offset = (index($0,$1)!=1) ? 1 : 0; print $(5-offset),$(6-offset),$(7-offset),$(3-offset)}'

cat lastb.out | awk '{$1 = (index($0,$1)==1 ? "" : "placeholder" FS) $1; $0=$0; print $5,$6,$7,$3}'

Все эти команды генерируют:

Oct 1 12:07 213.109.202.127
Oct 1 11:48 8.219.222.66
Oct 1 11:03 213.109.202.127
Oct 1 10:34 139.19.117.130
Oct 1 09:58 213.109.202.127
Oct 1 09:40 79.110.62.93
Oct 1 09:34 139.19.117.130

Вместо проверки атрибутов первого поля, вы могли бы (по крайней мере, для предоставленных образцов данных) проверить количество полей (NF):

  • NF==9 ==> 9 полей: мы ‘теряем’ первое поле, поэтому мы устанавливаем offset=1 или добавляем placeholder в начало строки
  • NF==10 ==> 10 полей: мы устанавливаем offset=0 или не добавляем ничего в начало строки

Ответ или решение

Ваша проблема заключается в том, что при парсинге вывода команды lastb с помощью awk, когда поле идентификатора пользователя (userID) пустое, смещаются ваши переменные, что приводит к неправильной интерпретации данных. В данном ответе мы рассмотрим, как можно решить эту задачу.

Проблема

Команда lastb выводит информацию о неудачных входах в систему и может содержать строки, где поле с идентификатором пользователя пустое. Это приводит к тому, что команда awk '{print $5,$6,$7,$3}', которая считает, что каждый элемент расположен в строго определенных позициях, не срабатывает как задумано.

Пример вывода

Рассмотрим следующий пример:

wpsadmin ssh:notty    213.109.202.127  Tue Oct  1 12:07 - 12:07  (00:00)
         ssh:notty    8.219.222.66     Tue Oct  1 11:48 - 11:48  (00:00)
quser    ssh:notty    213.109.202.127  Tue Oct  1 11:03 - 11:03  (00:00)

В данном примере, когда поле идентификатора пользователя пустое, ваши переменные в awk смещаются на одну позицию. Это приводит к тому, что при парсинге данное поведение приводит к неправильной интерпретации строк.

Решение

Для решения данной проблемы мы можем использовать подход с определением смещения (offset). Это позволит корректно извлекать данные из строк, независимо от наличия поля идентификатора пользователя.

Пример команд awk

Вы можете использовать следующий скрипт для обработки вывода:

lastb | awk '
{
    offset = ($1 ~ /^[[:space:]]*$/) ? 1 : 0; # Определяем смещение на основе наличия первого поля
    print $(5-offset), $(6-offset), $(7-offset), $(3-offset);
}'

Этот код делает следующее:

  • Проверяет, является ли первое поле пустым (содержит ли только пробелы).
  • В зависимости от результата проверки устанавливает значение смещения.
  • Извлекает необходимые поля, корректно обрабатывая их в зависимости от установленного смещения.

Альтернативный подход

Еще один метод — это добавление "заполнительного" поля в начале строки, когда первое поле отсутствует:

lastb | awk '
{
    if ($1 ~ /^[[:space:]]*$/) {
        $1 = "placeholder"; 
    }
    print $5, $6, $7, $3;
}'

При таком подходе вы просто добавляете заполнитель, что позволяет awk корректно считать количество полей в каждой строке.

Заключение

Предложенные выше решения помогут эффективно парсить вывод команды lastb, избегая проблем, связанных со смещением полей. Выбор подхода зависит от специфики ваших данных и личных предпочтений. Оба метода обеспечивают правильный вывод необходимой информации, включая дату и IP-адрес.

Таким образом, руководствуясь вышеизложенными рекомендациями, вы сможете успешно обрабатывать выходные данные команды и извлекать нужную информацию без ненужных ошибок.

Оцените материал
Добавить комментарий

Капча загружается...