Моя задача состоит в том, чтобы написать сценарий bash, используя awk, чтобы найти самый длинный вход в систему данного пользователя («все еще вошедший в систему» не считается) и напечатать month
day
IP
logon 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)
Пример вывода:
Apr
9
IP
731
(пояснение: 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
время входа в систему, и распечатать всю необходимую информацию в формате month
day
IP
logon time in minutes
, используя другой awk
.
Ошибки, которые я получаю при запуске этого кода: Куча синтаксических ошибок, когда я пытаюсь использовать grep
и awk
внутри оригинального awk
.
Поскольку ваша первоначальная команда grep по конвейеру удаляет строку, содержащую still logged in
, она должна быть доступна в вашем вводе, поэтому, пожалуйста, редактировать ваш вопрос, чтобы включить подобную строку в ваш пример ввода. Также покажите нам, каким должен быть вывод, если для данного пользователя нет ввода для обработки.
Если 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 с шаблоном и группами захвата (хотя ваш ответ читается как солнечный свет в пасмурный день)
Ах, вы правы в часах и минутах, моя ошибка, я неправильно понял, что ОП имел в виду под logon time in minutes
в начале вопроса - они описывают вывод, а не ввод.
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
) ?
Пожалуйста. ORS
и OFS
определены на справочной странице и руководстве awk, см. gnu.org/software/gawk/manual/gawk.html#Output-Separators, а ? :
— это просто тернарный оператор, как и во многих языках, см. https://en.wikipedia.org/wiki/%3F:. Дайте мне знать, если у вас возникнут какие-либо конкретные вопросы после прочтения этих ссылок.
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
Ваш код будет легче читать, если вы не сделаете отступ в своем awk-скрипте на 50 пробелов или что-то еще, и вы сделаете отступ блоков кода внутри
{...}
[airs.