Получите самое длинное время входа в систему для данного пользователя с помощью awk

Моя задача состоит в том, чтобы написать сценарий bash, используя awk, чтобы найти самый длинный вход в систему данного пользователя («все еще вошедший в систему» ​​не считается) и напечатать monthdayIPlogon time in minutes.

Пример ввода:./scriptname.sh username1

Содержание last username1:

username1       pts/        IP      Apr     2       ..      ..      ..      ..      (00.03)

username1       pts/        IP      Apr     3       ..      ..      ..      ..      (00.13)

username1       pts/        IP      Apr     5       ..      ..      ..      ..      (12.00)

username1       pts/        IP      Apr     9       ..      ..      ..      ..      (12.11)

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

Apr9IP731 (пояснение: 12 часов и 11 минут — всего 731 минута)

Я написал этот скрипт, но выскакивает куча ошибок, и я совсем запутался:

#!/bin/bash

usr=$1

last $usr | grep -v "still logged in" | awk 'BEGIN {max=-1;}
                                                {
                                                h=substr($10,2,2);
                                                min=substr($10,5,2) + h/60;
                                                }
                                                (max < min){
                                                max = min;
                                                }
                                                END{
                                                maxh=max/60;
                                                maxmin=max-maxh;
                                                ($maxh == 0 && $maxmin >=10){
                                                        last $usr | grep "00:$maxmin" | awk '{print $5," ",$6," ", $3," ",$maxmin}'
                                                        exit 1
                                                }
                                                ($maxh == 0 $$ $maxmin < 10){
                                                        last $usr | grep "00:0$maxmin" | awk '{print $5," ",$6," ",$3," ",$maxmin}'
                                                        exit 1
                                                }
                                                ($maxh < 10 && $maxmin == 0){
                                                        last $usr | grep "0$maxh:00" | awk '{print $5," ",$6," ",$3," ",$maxmin}'
                                                        exit 1
                                                }
                                                ($maxh < 10 && $maxmin < 10){
                                                        last $usr | grep "0$maxh:0$maxmin" | awk '{print $5," ",$6," ",$3," ",$maxmin}'
                                                        exit 1
                                                }
                                                ($maxh >= 10 && $maxmin < 10){
                                                        last $usr | grep "$maxh:0$maxmin" | awk '{print $5," ",$6," ",$3," ",$maxmin}'
                                                        exit 1
                                                }
                                                ($maxh >=10 && $maxmin >= 10){
                                                        last $usr | grep "$maxh:$maxmin" | awk '{print $5," ",$6," ",$3," ",$maxmin}'
                                                        exit 1
                                                }
                                                }'

Итак, небольшое объяснение того, как я себе это представлял:

После инициализации я хочу найти столбец (hh:mm) команды last $usr, сохранить h и min каждой строки, найти наибольшее число (в минутах, то есть это самое долгое время входа в систему).

После того, как я нашел самое длинное время входа в систему (в минутах, сохраненное в переменной max), мне нужно переформатировать единственный формат минут в hh:mm, чтобы иметь возможность использовать grep, снова использовать последнюю команду, но теперь только поиск строки (s), которые содержат max время входа в систему, и распечатать всю необходимую информацию в формате monthdayIPlogon time in minutes, используя другой awk.

Ошибки, которые я получаю при запуске этого кода: Куча синтаксических ошибок, когда я пытаюсь использовать grep и awk внутри оригинального awk.

Ваш код будет легче читать, если вы не сделаете отступ в своем awk-скрипте на 50 пробелов или что-то еще, и вы сделаете отступ блоков кода внутри {...} [airs.

Ed Morton 23.04.2022 15:06
редактировать ваш вопрос, чтобы сообщить нам, каким должен быть вывод, если пользователь входил в систему дважды в течение одной и той же самой продолжительной продолжительности каждый раз, но в разные даты или с разных IP-адресов (первый? последний? оба? что-то еще?). Кроме того, покажите другой IP-адрес в вашем примере, а не просто говорите «IP», чтобы мы могли видеть, КАКОЙ IP-адрес печатается в выводе.
Ed Morton 23.04.2022 15:12

Поскольку ваша первоначальная команда grep по конвейеру удаляет строку, содержащую still logged in, она должна быть доступна в вашем вводе, поэтому, пожалуйста, редактировать ваш вопрос, чтобы включить подобную строку в ваш пример ввода. Также покажите нам, каким должен быть вывод, если для данного пользователя нет ввода для обработки.

Ed Morton 23.04.2022 15:25
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
73
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Если gnu-awk доступен, вы можете использовать шаблон с 2 группами захвата для чисел в последнем поле. В блоке END напечатайте нужный формат.

Если в этом примере file содержит содержимое примера, а последний столбец содержит вход в систему:

awk '
match ($(NF), /\(([0-9]+)\.([0-9]+)\)/, a) {
  hm = (a[1] * 60) + a[2]
  if (hm > max) {max = hm; line = $0;}
}
END {
  n = split(line,a,/[[:space:]]+/)
  print a[3], a[4], a[5], max
}
' file

Выход

IP Apr 9 731

@EdMorton Я предположил, что чтение 12.11 означает «expl: 12 часов и 11 минут, всего 731 минута». Тем не менее, это действительные точки в ваших комментариях, но я изменил их на реализацию с использованием gnu-awk с шаблоном и группами захвата (хотя ваш ответ читается как солнечный свет в пасмурный день)

The fourth bird 23.04.2022 18:05

Ах, вы правы в часах и минутах, моя ошибка, я неправильно понял, что ОП имел в виду под logon time in minutes в начале вопроса - они описывают вывод, а не ввод.

Ed Morton 23.04.2022 23:12
Ответ принят как подходящий

awk не является оболочкой. Вы не можете напрямую вызывать такие инструменты, как last, grep и awk из awk, точно так же, как вы не можете вызывать их напрямую из C программы.

Используя любой awk в любой оболочке на каждом компьютере Unix и предполагая, что если несколько строк имеют максимальное время, которое вы хотите, чтобы все они были напечатаны, и что, если строки с отметкой времени не найдены, вы хотите напечатать что-то вроде No matching records (легкая настройка, если нет, просто сообщите нам ваши требования для этих случаев и включите их в пример вашего вопроса):

last username1 |
awk '
    /still logged in/ {
        next
    }
    {
        split($NF,t,/[().]/)
        cur = (t[2] * 60) + t[3]
    }
    cur >= max {
        out = ( cur > max ? "" : out ORS ) $4 OFS $5 OFS $3 OFS cur
        max = cur
    }
    END {
        print (out ? out : "No matching records")
    }
'
Apr 9 IP 731

Благодарю вас! не могли бы вы объяснить синтаксис «ORS» и «OFS»? Кроме того, как? : операторы работают (это делают это ? fnc иначе : fnc ) ?

David Gall 23.04.2022 16:10

Пожалуйста. ORS и OFS определены на справочной странице и руководстве awk, см. gnu.org/software/gawk/manual/gawk.html#Output-Separators, а ? : — это просто тернарный оператор, как и во многих языках, см. https://en.wikipedia.org/wiki/%3F:. Дайте мне знать, если у вас возникнут какие-либо конкретные вопросы после прочтения этих ссылок.

Ed Morton 23.04.2022 16:22

Тестирование команды last на моей машине:

Использование Red Hat Linux 7.8 Получил следующий вывод:

user0022 pts/1        10.164.240.158   Sat Apr 25 19:32 - 19:47  (00:14)
user0022 pts/1        10.164.243.80    Sat Apr 18 22:31 - 23:31 (1+01:00)
user0022 pts/1        10.164.243.164   Sat Apr 18 19:21 - 22:05  (02:43)
user0011 pts/0        10.70.187.1      Thu Nov 21 15:26 - 18:37  (03:10)
user0011 pts/0        10.70.187.1      Thu Nov  7 16:21 - 16:59  (00:38)
astukals pts/0        10.70.187.1      Mon Oct  7 19:10 - 19:13  (00:03)
reboot   system boot  3.10.0-957.10.1. Mon Oct  7 22:09 - 14:30 (156+17:21)
astukals pts/0        10.70.187.1      Mon Oct  7 18:56 - 19:08  (00:12)
reboot   system boot  3.10.0-957.10.1. Mon Oct  7 21:53 - 19:08  (-2:-44)
IT       pts/0        10.70.187.1      Mon Oct  7 18:50 - 18:53  (00:03)
IT       tty1                          Mon Oct  7 18:48 - 18:49  (00:00)
user0022 pts/1        30.30.30.168     Thu Apr 16 09:43 - 14:54  (05:11)
user0022 pts/1        30.30.30.59      Wed Apr 15 11:48 - 04:59  (17:11)
user0022 pts/1        30.30.30.44      Tue Apr 14 19:03 - 04:14  (09:11)

Найденный формат времени DD+HH:MM появляется только тогда, когда DD не равен нулю.

Найдены дополнительные технические пользователи: IT, system, reboot нужно отфильтровать.

Предлагаемое решение:

last | awk 'BEGIN {FS = "[ ()+:]*"}
/reboot|system|still/{next}
{ print $5 OFS $6 OFS $3 OFS $(NF-1) + ($(NF-2) * 60) + ($(NF-3) * 60 * 24)}
' |sort -nk 4| head -1

Результат:

Apr 15 30.30.30.59 85991

Другие вопросы по теме