Awk - рецепты
Материал из rrv-Wiki.
grep полезные ключи
-i игнорировать регистр
-A4 выводить еще 4 строки следующие за найденной
-v выводить все кроме найденных
поиск в файлах в директории:
egrep то_что_ищем ./*
Внешние переменные
Для того что бы передать внешнюю переменную можно воспользоваться конструкцией -v t=$temp то есть с помощью ключа -v мы передали внешнюю переменную (переменную shell) '$temp', например:
temp="Значение"
cat test.txt | /usr/bin/awk -v t=$temp 'BEGIN {FS="."} {if($5>0) print t" "$4"="$5}'
Решение ошибок типа /usr/bin/egrep: Argument list too long
Поиск (удаление, копирование и др)в длинных списках решается с помощью xargs.
Простой запрос:
egrep -i строкапоиска ./* /usr/bin/egrep: Argument list too long
Запрос решающий проблему длинного списка:
find ./ -type f | xargs egrep -i строкапоиска
Сжатие в архив всех папок в директории
Необходимо сжать все папки в директории /home/backup_all/ по одной, а затем удалить оригиналы
home_dir="/home/backup_all/"
cd home_dir; $ls -la grep ^d | awk '{print $9}' | grep -v ^"\." | awk -v t=$home_dir '{system ("tar cfz "$1".tar.gz "t$1" && rm -r "t$1)}'
if
Поиск строчек с определенным регулярным выражением:
#поиск строк содержащий " - " (пробел тире пробел)
echo "НАТАЛЬЯ СЕНЧУКОВА - СЛУЖЕБНЫЙ РОМАН" | awk '{if ($0 ~ /.+ - .+/) {print $0}}'
Пример поиска точного слова в определенном столбце и работу с числами:
#Поиск Фамилии (слова Иванов именно в первом столбце) и возраста старше 30 лет ( четвертый столбец)
echo "Иванов Иван Иванович 45 лет" | awk '{if (($1=="Иванов")&&($4>30)) print $0}'
Циклы Shell-а
Немного не по теме, но часто требуется.
min_num=1 max_num=10 i=$min_num while [ $i -le $max_num ]; do echo "$i" i=`expr $i + 1` # в зависимости от shell также подходит i=$(($i + 1)) или i=$[i+1] done
Перебор значений от 0000 до 9999 с помощью printf
#!/bin/sh imax=9999 i=0 while [ $i -le $im ]; do echo $i printf %04d $i i=`expr $i + 1` done
Получение случайных чисел jot
можно использовать jot, например получение 5 случайных чисел от 1 до 100:
$ jot -r 5 1 100 84 69 43 12 25
Вот еще один пример, получить одно случайное число о 30 до 60 и выдержать паузу на это кол-во секунд:
$ sleep `jot -r 1 30 60`
Итоги
Подсчет объема всех mp3 файлов в текущей директории и во всех вложенных в нее папках:
find ./ | grep -i "\.mp3"$ | awk '{system ("ls -la \""$0"\"")}' | awk 'BEGIN{k=0} {k=k+$5} END{print k}'
Подсчет кол-ва несжатых wav файлов в текущей директории и во всех вложенных в нее папках:
find ./ | grep -i .wav$ | awk '{system ("file \""$0"\"")}' | grep PCM | awk 'BEGIN{k=0}{k=k+1}END{print k}'
Вывод партиций заполненных более чем на 90%
df -h | awk '{if (/^\/./) print $1" "$6" "$5}' | awk 'BEGIN {FS="%"} {print $1}' \
| awk '{if ($3>90) print "WARNING "$1" "$2" "$3"%"}'
Время
Ключи для дней недели:
date --date $DD +%A # DOW complete пример: воскресенье date --date $DD +%a # DOW abreviated пример: вс date --date $DD +%u # DOW (1..7) 1 is monday пример: 7 date --date $DD +%w # DOW (0..6) 0 is sunday пример: 0
Время минус сколько то дней минут и др
Используем ключ -v. Например время минус 1 день и вывод в виде годмесяцдень
date -v-1d +%Y%m%d
Старый вариант
Текущее время минус 1 час
date +%s | awk '{k=$1-3600; system ("date -r "k)}'
Начало предыдущего часа в формате вида 21-09-2007_11-00 (день-месяц-год_час_минута)
date +%s | awk '{k=$1-3600; system ("date -r "k" +%d-%m-%Y_%H-00")}'
Mysql
Оптимизация всех таблиц mysql
#!/bin/sh
p="MYSQL_PASSWORD"
echo "show databases;" | mysql -u root --password="$p" | grep -v "^Database" | awk '{print ("use "$0" ; show tables;")}' \
| mysql -u root --password="$p" \
| awk 'BEGIN {FS="_"}{if ($1 == "Tables") {if ($2 =="in" ) {printf "USE \`"$3; for (i = 4; i < 10; i++) {if ($i != "") printf ("_"$i)}; print ("\`;")} else {print ("OPTIMIZE TABLE \`"$0"\`;")}} else {print ("OPTIMIZE TABLE \`"$0"\`;")}}' \
|mysql -u root --password="$p" > result_optimize.txt
Ремонт всех баз данных mysql кроме некоторых
#!/bin/sh
#Скрипт ремонтирует все базы mysql кроме HTTPD_LOGS и выводит только ошибки восстановления
p="пароль_mysql"
echo "show databases;" | mysql -u root --password="$p" | grep -v "^Database" | grep -v "HTTPD_LOGS" \
| awk -v p="$p" '{system ("mysqlcheck -u root --password=\""p"\" -e --auto-repair --databases "$0)}' | grep -v "OK"
Удаление повторяющихся строк
Не awk но бывает полезно, емли нужно вывод из потока отсортировать и убрать все повторяющиеся строки:
cat file.txt | sort | uniq
Подсчет повторяющихся строк
cat file.txt | sort | uniq -с
Преобразование wav файлов в mp3
# Скрипт создает структуру каталогов в другом месте
# затем ищет все wav файлы в указанной директории, определяет что они не сжатые
# сжимает их, причем имя становится name.wav.mp3, то есть к имени файла добовляется .mp3,
# а оригиналы копирует в подготовленное дерево дирикторий
#Переходим в каталог
cd "/home/samba/archives/Архив\ рекламы\ 2004/"
#создаем структуру каталогов в /home/samba1/Архив рекламы 2004/
find ./ -type d | awk '{system ("mkdir -p \"/home/samba1/Архив рекламы 2004/"$0"\"")}'
#ищем все wav файлы, сжимает их, а оригиналы копирует в подготовленное дерево дирикторий
find ./ | grep -i .wav$ \
| awk '{system ("file \""$0"\""); print $0}' \
| awk '/PCM/ {getline; system ("/usr/local/bin/lame -m s -b 256 \""$0"\" \""$0".mp3\" && mv \""$0"\" \"/home/samba1/Архив рекламы 2004/"$0"\"")}'
Поиск пакетов с удаленными файлами
Один раз случайно удалил папку /usr/X11R6 во время установки пакета gd. Помогла вот такая уродливая последовательность команд:
pkg_info | awk '{system("pkg_info -L "$1)}' | awk '/X11R6|Information/ {print $0}' \
| tr "\n" " " | awk 'BEGIN {FS = "Information\ for "} { for (i = 1; i < NF+1; i++) print $i }' \
| grep /X11R6 \
| awk 'BEGIN {FS = ": | "} { system ("echo "$1" >> /tmp/rm.list"); for (j = 2; j < NF+1; j++) system ("ls "$j" 2>> /tmp/rm.list ") }' \
> /dev/null
В файле /tmp/rm.list можно было обнаружить по сообщениям ошибок какие порты необходимо пересобрать.
Поиск директорий размер которых привышает 3Gb
Глубина поиска 7 по директории /home. Будут отображены папки больше 3Gb
du -h -d 7 /home \
| awk ' /^ *[0-9]+(,[0-9]+)*G/ {printf "%s ", $1 ;for (j = 2; j < NF+1; j++) printf "%s", $j; print""}' \
| awk 'BEGIN {FS="G "} {if ($1>3) print $0}' | less
Для поиска парок измеряемых гигабайтами (>1Gb):
du -h -d 7 /home | grep "^ *[0-9]*G"
Замена части строк в текстовых файлах находящихся в одной директории
Мне понадобилось заменить время в расписании находящихся во многих текстовых файлах части строк вида: "00:20", "00:30", "00:40", "00:50" на тоже время плюс 2 мин то есть "00:22" и т.д. Это сделал скрипт:
find ./ -type f | sed "s/\.\///g" | \
awk '{system ("cat \""$0"\" | sed s/:20/:22/g | sed s/:30/:32/g | sed s/:40/:42/g | sed s/:50/:52/g > \"../new/"$0"\"")}'
Результат помещается в папку ../new/
Создание html таблицы по времени создания файлов в директории
Скрипт1:
# подсчитывает кол-во файлов в директории и всех вложенных папках осзданных в октябре
# и формирует таблицу формата html
# по вертикали месяца, по горизонтали 24 часа с интервалом в минуту на пересечении колво файлов созданных за эту минуту.
echo "<html><table border=1>"
find ./ -type f | awk '{system ("ls -la "$0" | grep окт")}' | tr ":" " " \
| awk 'BEGIN {printf "<tr><td> </td>"; for(j=0;j<=23;j++) {for(k=0;k<=59;k++) printf "<td>%d:%d</td>", j, k}; printf "</tr>\n"}{dat[$6+0,$8+0,$9+0]++}END{for(i=1;i<=31;i++) {printf "<tr><td>%d</td>", i; for(j=0;j<=23;j++){for(k=0;k<=59;k++) printf "<td>%d</td>", dat[i,j,k]}; printf "</tr>\n"};}'
echo "</table></html>"
Скрипт2:
# подсчитывает кол-во файлов в директории и всех вложенных папках осзданных в октябре,
# причем файлы должны содержать текст "fmreklama.ru"
# и формирует таблицу формата html
# по вертикали месяца, по горизонтали 24 часа с интервалом в минуту на пересечении колво файлов созданных за эту минуту.
echo "<table><tr>"
find ./ -type f | awk '{system ("ls -la "$0); print $0}' \
| awk '/окт/ {getline; system ("egrep -c \"fmreklama.ru\" \""$0"\""); print $0}' \
| awk '{t=$0; getline; if (t > 0) system ("ls -la "$0" | grep окт")}' | tr ":" " " \
| awk 'BEGIN {printf "<tr><td> </td>"; for(j=0;j<=23;j++) {for(k=0;k<=59;k++) printf "<td>%d:%d</td>", j, k}; printf "</tr>\n"}{dat[$6+0,$8+0,$9+0]++}END{for(i=1;i<=31;i++) {printf "<tr><td>%d</td>", i; for(j=0;j<=23;j++) {for(k=0;k<=59;k++) printf "<td>%d</td>", dat[i,j,k]}; printf "</tr>\n"};}'
echo "</table></html>"
Подсчёт количества файлов в заданной директории
Скрипт1:
echo $1
#
find $1 -type d -depth 1 | awk '{print $0; system("find \""$0"\" | /home/count1.sh")}'
Скрипт2:
#
awk 'BEGIN{k=0}{k=k+1}END{print k}'
Переименование файлов с преобразованием кодировки (из koi8 в cp1251)
Ключ -c в iconv заставляет iconv пропускает ошибки, символы которые не может преобразовать.
find ./ -type d | awk '{system ("echo \""$0"\" | iconv -c -f koi8-r -t cp1251")}' | awk '{system ("mkdir -p \"../new/"$0"\"")}'
find ./ -type f | awk '{printf $0"====="; system ("echo \""$0"\" | iconv -c -f koi8-r -t cp1251")}' \
| awk 'BEGIN {FS="====="} {system ("mv \""$1"\" \"../new/"$2"\"")}'
Переформатируем файлы сайта в папке rrv из кодировки cp-1251 в utf-8
Создаем копию дерева деорикторий в папке utf-8
mkdir ./utf-8 && cp -r ./rrv ./utf-8/
Ищем все возможные расширения
find ./rrv/utf-8/mayak -type f | grep -v \.svn | sed 's/.*\.//' \
| sort | awk '{printf ("| grep -v "$0"$ ")}'
Потом удаляем ненужные типы расширений (например картинки) копируем и вставляем в следующую строку
find ./rrv -type f | grep -v svn | grep -v JPG$ \
| grep -v css$ | grep -v dataModel$ | grep -v db$ | grep -v gif$ | grep -v htc$ \
| grep -v jpg$ | grep -v old$ | grep -v png$ | grep -v tar$ | grep -v tpl$ \
| grep -v ttf$ | grep -v wsdlDataModel$ \
| awk '{system ("iconv -c -t UTF-8 -f CP1251 \""$0"\" > \"./utf-8/"$0"\"")}'
Проверка работоспособности HTTP сервера
Для проверки запускаем по крону скрипт:
(sleep 2 && echo "HEAD / HTTP/1.0" && echo && sleep 2) \
| telnet r-info.net 80 2>/dev/null | grep "HTTP/.*\..* 200 OK" \
| awk 'BEGIN{k=0}{if ($0~" 200 OK") k=1}END{if (k==0) print "Сервер r-info.net недоступен!"}'
Не забудем указать полные пути для всех команд: awk, telnet, ...
Результатом работы скрипта будет письмо пользователю от которого был запущен скрипт.
Скрипт, который переворачивает файл (последняя строка станет первой и т.д.)
cat file.txt | awk 'BEGIN {FS="\n"; RS=""; OFS=""} {for (i=NF; i>0; i--) print $i;}'
В линуксе для этой цели есть утилита tac
Скрипт парсит html
parser.sh
#!/bin/sh #Скрипт делает следующее: #1. Определяет путь до parser.sed, скрипта написанного на sed который должен находится в той же директории, что и этот скрипт #2. Определяет дату на день вчерашний в виде 20090312 (год месяц день) #3. Скачивает вчерашний плейлист европы+ с сайта http://www.moskva.fm/stations/FM_106.2/20090312 #4. Выделяет парсит с помощью скрипта (parser.sed) написанного на sed html-файл выделяя время выхода в эфир, исполнителя и песню #5. Сортирует в обратном порядке (т.к. там плейлист в обратном порядке) делая 2 строчки на каждую песню # первая строка время выхода, вторая ИСПОЛНИТЕЛЬ - НАЗВАНИЕ ПЕСНИ #6. Переводим кодировку из utf-8 в koi8-r PATHSCRIPT=`echo $0 | /usr/bin/sed -n "s/parser.sh$/parser.sed/p"` D=`date +%s | /usr/bin/awk '{k=$1-86400; system ("date -r "k" +%Y%m%d")}'` /usr/local/bin/lynx -accept_all_cookies -source http://www.moskva.fm/stations/FM_106.2/$D | \ /usr/bin/sed -n -f $PATHSCRIPT | \ /usr/bin/awk 'BEGIN {FS="\n"; RS=""; OFS=""} {for (i=NF; i>0; i=i-3) print ($(i-2)"\n"$i" - "$(i-1));}' | \ /usr/local/bin/iconv -с -f utf-8 -t koi8-r > 1.txt
parser.sed
/^ <td class="number">/ {
s/[ ]*<td class="number">//
s/<\/td>//
p
}
/<a href="\/artist\/.*" class="artist">.*<\/a><\/p>/ {
s/[ ]*<a href="\/artist\/.*" class="artist">//
s/<\/a><\/p>//
p
}
/onclick=\"return manageSong(this)\"/{
s/[ ]*<a href="http:\/\/www\.moskva\.fm\/artist\/.*" class="song">//
s/<\/a> <a href=".*" class="add" onclick="return manageSong(this)"><\/a>
//
p
}
Возможности egrep, выделение последлвательности TTH
Не много не в тему, но может пригодится.
Имеем строку вида:
magnet:?xt=urn:tree:tiger:TL5GMCI5ZSYCRKZY35COUOPNZC47DWOTEU44UKQ&xl=1465516032&dn=The%20international.avi
Требуется вычленить tth сумму.
Вариант 1. (Сложный):
$ echo "magnet:?xt=urn:tree:tiger:TL5GMCI5ZSYCRKZY35COUOPNZC47DWOTEU44UKQ&xl=1465516032&dn=The%20international.avi" \
| awk 'BEGIN{FS="urn:tree:tiger:|&xl="}{print $2}'
TL5GMCI5ZSYCRKZY35COUOPNZC47DWOTEU44UKQ
Вариант 2. (Простой используя egrep)
$ echo "magnet:?xt=urn:tree:tiger:TL5GMCI5ZSYCRKZY35COUOPNZC47DWOTEU44UKQ&xl=1465516032&dn=The%20international.avi" \
| egrep -o [A-Z0-9]{39}
TL5GMCI5ZSYCRKZY35COUOPNZC47DWOTEU44UKQ
Загрузка системы на FreeBSD в %
/sbin/sysctl vm.loadavg | /usr/bin/awk '{printf("%d\n", $4*100)}'
Любителям калькулятора dc посвещается:
sysctl vm.loadavg | awk '{printf("2k 100 %s * p", $4)}' | sed "s/,/./g" | dc | awk 'BEGIN{FS="."}{print $1}'
Получение списка файлов в директории в случайном порядке
#!/bin/sh
#Подготавливаем псевдослучайные значения для srand из двух чисел сек. и мин.
T1=`/bin/date +%S%M`
T2=`/bin/date +%M%S`
Подсчитываем кол-во файлов в директории
L=`ls | wc -l | sed "s/ //g"`
# Собственно получаем случайный список путем замены каждого значения списка со случайной позицией из этого же списка
ls | awk '{printf $0"-=-=-=-=-"}' \
| awk -v s=$T1 -v m=$T2 -v l=$L 'BEGIN{FS="-=-=-=-=-"; srand((s+1)*(m+1)) }for (i = 1; i < l; i++){k=int((l-1)*rand()+1); p=$k; $k=$i; $i=p}; for (i = 1; i < l; i++) {printf $i"+"}}'
Кусок скрипта фильтрующий строки содержащие только ip адрес, скрипт сортирует ip адреса и удаляет дубли
cat ip.list | grep "^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$" | sort | uniq
Удобная утилита замены tr
Почитать описание синтаксиса tr
Правильный поиск всех пользователей зарегистрированных в системе
getent passwd | awk 'BEGIN{FS=":"}{print $1}'
Подсчет кол-ва подключений на один порт
sockstat | grep 8000 | wc -l
Но если каждый клиент создает по 4 подключения на 1 порт, и еще сам процесс создает четыре сокета на порту 8000, то поручается, что надо подсчитать кол-во записей порта 8000 поделить на 4 и вычесть 1, реализуем:
sockstat | grep 8000 | wc -l | awk '{system ("expr "$1 " / 4 - 1");}'
"Придумывание" паролей
Возникла потребность придумать пароли для сотен почтовых ящиков. Родилась идея, воспользоватся для генерации паролей, ограниченной десятью символами md5 суммой от имени почтового ящика плюс некоторая фраза (в моем случае "соль"):
cat mail_list.txt | awk '{system ("md5 -s соль"$0)}' \
| awk '{print $4}' | cut -c 1-10 | paste mail_list.txt - \
> mail_pass_list.txt
Дублирование прав доступа
Программисты прислали архив движка сайта, но права на все папки и файлы были неправильно установлены. для копирования прав используем скрипты:
Для начала установим права 755 на все папки новой версии:
find /home/site_new -type d -exec chmod a+xr,u+w {} \;
Права на все файлы новой версии:
find /home/site_new -type f -exec chmod a+r,u+w {} \;
Ищем директории доступные для записи группе (www) и устанавливаем на новый движок:
find /home/site -type d \( -perm -2 -o -perm -20 \) \
| awk 'BEGIN{FS="^\."}{system ("chmod g+w \"/home/site_new"$2"\"")}'
Если требуется делаем тоже и для файлов:
find /home/site -type f \( -perm -2 -o -perm -20 \) \
| awk 'BEGIN{FS="^\."}{system ("chmod g+w \"/home/site_new"$2"\"")}'
Еще примеры для find ищем тут:Find - поиск файлов по правам доступа.

