Инструменты пользователя

Инструменты сайта


awk

AWK

Программа awk автоматически делит каждую прочитанную строку на поля - строки символов разделенные знаками табуляции. Этим полям она присваивает имена $1, $2, $3 и т.д., $NF переменная содержащая количество полей в строке.

Пр. who | awk '{print $1,$4}'
Пр. df -h | grep /dev/ | awk '{print $1,$5}'

Параметр -F позволяет задать разделитель.

Пр. tail -n4 /etc/passwd | awk -F: '{print $1}'

Переменная NR хранит номер текущей строки.

Пр. tail -n4 /etc/passwd | awk -F: '{print NR, $1}'
Пр. cat /etc/passwd | awk -F: '{print NR, "User:",$1,",shel:",$7}'

Поле $0 представляет всю входную строку целиком.

В операторе print значения разделяемые запятыми печатаются через разделитель выходных полей, по умолчанию это пробел.

Проверим есть ли пользователь с именем root.
Пр. awk -F: '$1=="root"' /etc/passwd
Проверим есть ли пользователи без пароля.
Пр. awk -F: '$2==""' /etc/passwd
аналогично можно использовать:
awk -F: '$2 ~ /^$/' /etc/passwd Второе поле совпадает с пустой строкой, ~ указывает на использование регулярного выражения, которое заключено между символами косой черты.
awk -F: '$2 !~ /./' /etc/passwd Второе поле не соответствует никакому символу.
awk -F: 'length($2)==0' /etc/passwd Длина второго поля равна 0. length встроенная функция awk, считающая длину строки.


awk 'NF % 2 != 0' /etc/passwd Печатать, если число полей четно.
awk 'NF % 2 == 0' /etc/passwd Печатать, если число полей не четно.

Пр. вывести диск, если его заполненность больше 70%

df | awk '($3*100/$2) > 70 {print $1}'

Функция substr(s,m,n) возвращает строку s, начиная с позиции m, длиной n символов.

Пр. date | awk '{print substr($4,1,5)}'
12:07

Шаблоны BEGIN и END.

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

Арифметические выражения awk.

Пр. {s=s+$1}
Пр. awk '{s = s+ substr($8,6,9)} END {print s, s/NR}' ping.log
Пр. df | awk '{s = $4*100/$2}  {print "На диске:", $1,"свободного места:", substr(s,1,2) "%"}' | grep /sd

Встроенные переменные awk.

FILENAME имя текущего входного файла
FS разделитель полей, пробел или табуляция по умолчанию
NF количество полей во входной записи
NR номер выводимой записи
OFMT формат вывода для чисел
OSF разделитель полей входных строк
OSR разделитель выходных строк
RS разделитель входных записей

Операторы awk

= += -= *= /= %= присваиваие
|| логическое или: expr1 || expr2 истино, если истинен любой из операндов
&& логическое и: expr1 && expr2 истино, если истины оба операнда
Пр. awk 'NR==13 || NR==12' /etc/passwd
Пр. awk 'NR==13 && NR==13' /etc/passwd
! инвертирование результата выражения
> >= < <= == != ~ !~ операторы сравнения; ~ - совпадение, !~ - не совпадение
+ - плюс и минус
* / % умножение, деление, вычитание остатка
++ -- инкремент и декремент

Операторы управления.

if (условие)
	оператор1
else
	оператор2
for (выражение1; условие; выражение2)
	оператор
Пр. for (i = 2; i <= NF; i++)
выражение1
	while (условие) {
		оператор
		выражение2
	}

Массивы

Пр. печатает файл /etc/passwd в обратном порядке.

awk ' {line[NR] = $0}
END {for (i = 1 ; i!=NR ; i++) print line[i]} ' /etc/passwd
 
awk '{line[NR]=$0} {i=NR} END {while (i!=0) {print line[i] i--}}' /etc/passwd

Массивы не требуют объявления; размер массива ограничен объемом оперативной памяти.

Встроенные функции в awk.

cos(expr) косинус expr
exp(expr) экспоненциальная функция
getline() вывод очередной строки, возвращает 0, если достигнут конец файла, иначе 1
index(s1,s2) положение строки s2 в строке s1, возвращает 0, если подстрока не найдена
int(expr) целая часть expr, дробная часть отбрасывается
Пр. df | awk ' {if (index($1,"/dev/s")==1) print $1,int($4*100/$2)}'
length(s) длина строки s
log(expr) натуральный логорифм expr
sin(expr) синус expr
split(s,a,c) разбиение строки s на элементы a[1]...a[n] по символу c, возвращает n
sprintf(frm,...) формотировать согласно спецификации frm
substr(s,n,m) подстрока строки s длиной n, начиная с позиции m.

Ассоциаивные масивы

При обработке данных возникает необходимость хранения набора пар имя-значение sum

usie 100
John 200
Mary 300
Mary 400
John 500
Susie 600
Mary 700


awk '{sum[$1]+=$2} END {for (name in sum) print name,sum[name]}' sum 

Mary 1400
John 700
usie 100
Susie 600

Переменные в awk

#!/bin/bash

log="/var/log/fail2ban.log"
day=$(date +%Y-%m-%d)

awk -v d=$day '{if ($1==d && $7=="Ban") ip[$8]+=1} END {for (i in ip) print  ip[i], i}' $log | sort -r
#или
awk  '{if ($1==d && $7=="Ban") ip[$8]+=1} END {for (i in ip) print  ip[i], i}' d=$day $log | sort -r

Полезности

Ищем первых 5 пользователей по потреблению памяти в %

ps aux | awk '{mem[$1]+=$4} END {for (user in mem) print user,mem[user] }' | sort -rdk2 | head -n5

Выводим диски на которых использовано более 60% памяти

df  | awk '{use=($3*100/$2)}{if(use>6&&$1~/\/dev*/)print$1,int(use)"%"}'

Вывести все значимые строки конфига(исключаем комментарии и пустые строки)

awk '{if ($0!~/^$/ && $0!~/^#/) print $0}' /etc/adduser.conf 

Топ заблокированных ip в fail2ban

awk '{if($7=="Ban")ip[$8]+=1 } END  {for (i in ip) print ip[i],i}' /var/log/fail2ban.log | sort -r
awk.txt · Последние изменения: 2015/11/12 09:00 — sander