sed и awk (учебное пособие), примеры использования awk

Опубликовано: 2018-06-08

Потоковый редактор sed


Команда имеет формат:

     sed [ -n ] [ -e script ] [ -f sfile ] [ files ]

Команда копирует файлы (по умолчанию со стандартного входа) на стандартный выход, редактирует их в соответствии со своими(!) командами, размещенными в "script" (в командном файле или строке редактора [а не shell!]). По флагу "-f" берет берет файл команд из файла "sfile"; Если есть только опция "-e script", то флаг "-e" можно опустить. Флаг "-n" подавляет вывод (происходящий по умолчанию). "script" состоит из команд редактирования, по одной в строке, имеющих формат:


     [ addr [ , addr ] ] cmd [ args ]

"sed" циклически преобразует входные строки в выходные.
Адреса "[ addr [ , addr ] ]" - это либо номера строк, либо последняя строка (символ "$"), либо регулярные выражения в стиле редактора "ed":


Для следующих (основных) функций (команд) максимальное число допустимых адресов указано в скобках.

(1)a\ text Добавляет text после указанной строки

who

root tty1 Mar 13 17:23
mas tty2 Mar 13 18:50
sae tty6 Mar 13 17:24
sae tty5 Mar 13 17:24

who | sed '2a\ новая строка'

root tty1 Mar 13 17:23
mas tty2 Mar 13 18:50
новая строка
sae tty6 Mar 13 17:24
sae tty5 Mar 13 17:24

(2)b label Осуществляет переход к команде ("cmd") "label:cmd". Если метка ("label") отсутствует, то переход на конец командного файла.

who | sed '2a\новая строка b lb 2d : lb 3d'

root tty1 Mar 13 17:23
mas tty2 Mar 13 18:50
новая строка
sae tty5 Mar 13 17:24

(2)c\ text Удаляет выбранные строки и заменяет их на "text'.

who | sed '/sae/ c\cтрока замены'

root tty1 Mar 13 17:23
mas tty2 Mar 13 18:50
строка замены
строка замены

(2)d Удаляет найденные строки

who | sed '2,4d'

root tty1 Mar 13 17:23

(1)i\ text Вставляет "text" на место выбранной строки. (сравните с "a\")

who | sed '2i\новая строка'

root tty1 Mar 13 17:23
новая строка
mas tty2 Mar 13 18:50
sae tty6 Mar 13 17:24
sae tty5 Mar 13 17:24

(2)p Выводит найденные строки (используется с флагом "-n").
(1)q Выходит из "sed".
(2)r rfile Читает файл "rfile" и выдает на выход.
(2)s/reg_expr/rpl/flags Заменяет регулярное выражение "reg_expr" на "rpl" с учетом флагов "flags":

who | sed 's/t/T/'

echo

who | sed 's/t/T/g'

rooT tty1 Mar 13 17:23
mas Tty2 Mar 13 18:50
sae Tty6 Mar 13 17:24
sae Tty5 Mar 13 17:24

rooT TTy1 Mar 13 17:23
mas TTy2 Mar 13 18:50
sae TTy6 Mar 13 17:24
sae TTy5 Mar 13 17:24

(2)y/str1/str2/ Заменяет все вхождения символов "str1" соответствующими символами "str2". Длины строк должны быть одинаковыми.

who | sed 'y/sae/SAE/'

root tty1 MAr 13 17:23
mAS tty2 MAr 13 18:50
SAE tty6 MAr 13 17:24
SAE tty5 MAr 13 17:24

(2)! Cmd Команда(ы) "cmd" применяются к невыбранным строкам.

who | sed '2,4!d'

mas tty2 Mar 13 18:50
sae tty6 Mar 13 17:24
sae tty5 Mar 13 17:24

(1)= Выдает номера строк.

who | sed =

1
root tty1 Mar 13 17:23
2
mas tty2 Mar 13 18:50
3
sae tty6 Mar 13 17:24
4
sae tty5 Mar 13 17:24

(2){ } Скобки группируют команды.

Язык обработки шаблонов awk

awk - команда контекстного поиска и преобразования текста. Она - фильтр. Ее можно рассматривать как оболочку "awk" в оболочке "shell".

Структура awk-программы
Программа состоит из операторов (правил), имеющих вид:
шаблон {действие}
шаблон {действие}
...

Частные случаи:

Действие может состоять из последовательности операторов, разделяемой ";" или переводом строки или закрывающей скобкой.
Возможны комментарии (как в shell "#.........").

Для дальнейших примеров возьмем входной файл "f-awk" ( фамилия инициалы год-приема-на-работу возраст ):
Иванов И.И.        1980     50
Петров А.В.         1979     40
Сидоров С.К.       1979     40
Хведоров И.Х.     1970     60

# выдает весь текст;
awk '{print}' f-awk

# выдает строки, где есть "до".
awk '/до/ {print}' f-awk

# выдает строки, где есть "до"
awk '/до/ {}' f-awk

awk '/до/ {print("Привет!")}' f-awk
Иванов И.И. 1980 50
Петров А.В. 1979 40
Сидоров С.К. 1979 40
Хведоров И.Х. 1970 60

Сидоров С.К. 1979 40
Хведоров И.Х. 1970 60

Сидоров С.К. 1979 40
Хведоров И.Х. 1970 60

Привет!
Привет!

Существует два оператора специального вида ("BEGIN"-начальные установки и "END" - "последействия"):
BEGIN {действие}
шаблон {действие}
шаблон {действие}
. . .
END {действие}

Вызов awk
Возможны два основных варианта:
  1. awk [-Fc] 'prog.awk' [files]

    Это простейший случай, когда программа (заключенная в кавычки " ' ") находится в теле команды, "-Fc" - флаг, меняющий стандартный разделитель полей на "c" "file" - имя файла исходных данных, при его отсутствии - со стандартного входа. (Этот формат использован в начальных примерах).


    cat f-awk | awk '/до/ {print}'

    и

    awk '/до/ {print}' < f-awk


    дают результат, аналогичный

    awk '/до/ {print}' f-awk


    Для демонстрации действия флага "-Fc" рассмотрим вызовы:

    awk '/до/ {print($2)}' f-awk

    awk -F0 '/до/ {print($2)}' f-awk

    С.К.
    И.Х.
    6

    Первая команда "awk" выведет вторые поля (благодаря позиционной переменной "$2") строк, содержащие "до". (Кстати, позиционная переменная "$0" соответсвует всей строке). Во втором случае, благодаря флагу "-F" стандартные разделители заменены на символ "0", т.е. теперь выбранные строки воспринимаются, как разбитые на следующие поля:

    Сидоров С.К. 1979 40
    ---------------------^--------------------
    1-е поле 2-е поле (пусто)

    Хведоров И.Х. 1970 60
    -----------------^---^--------------------
    1-е поле 2-е 3-е поле (пусто)

  2. awk [-Fc] -f prog.awk [files]

    Флаг "-f" говорит о том, что awk-программу надо брать из файла, имя которого указано следом (имя может быть произвольным и расширение ".awk" добавлено здесь просто из эстетических соображений).


awk-переменные и выражения

В языке awk выделяются две группы переменных: предопределенные и декларированные в программе. Исходные значения предопределенных переменных устанавливаются интерпретатором awk в процессе запуска и выполнения awk-программы.


NR - номер текущей строки
NF - число полей в текущей строке
RS - разделитель строк на вводе, умолчане - "\0"
FS - разделитель полей на вводе, умолчане - пробел и/или табуляция
ORS - разделитель строк на выводе, умолчане - RS
OFS - разделитель полей на выводе, умолчане - FS
OFMT - формат вывода чиcл, умолчане - "%.6g"
FILENAME - имя входного файла.

Прочим переменным пользователь может присваивать начальные значения. По умолчанию "0" или пустая строка (что здесь равнозначно!).
Типы переменных:
Интерпретатор awk рассматривает переменную как строковую, пока не возникает необходимость выполнить операции:

awk '{a = $3 $4; print a}' f-awk

198050
197940
197940
197060

awk '{a = $3+$4; print a}' f-awk

2030
2019
2019
2030

awk '{}END {a = 2 + 2 ; print a}' < f-awk

awk '{}END {a = 2 + "2" ; print a}' < f-awk

awk '{}END {a = 2 + "два" ; print a}' < f-awk

awk '{}END {a = "два"+"два" ; print a}' < f-awk

awk '{}END {a = 2.2 + 2.000 ; print a}' < f-awk

4
4
2
0
4.2

Массив не объявляется, а начинает существовать в момент первого использования. Индекс массива - любое ненулевое значение или строка. Массивы ассоциативные, т.е. не по вычисляемому индексу, а по совпадению содержания, например:

day [Jan][31] = Mon
day [Feb][01] = Tue
day [Feb][02] = Wed

Массивы удобно использовать при суммированиях, например записи выплат имеют вид (файл "p-1"):
John 100 Mary 200 Mary 200 John 100 John 300

awk '{sum[$1] += $2; print $1 sum[$1]} ' < p-1

Результат (поименный нарастающий итог):
John100
Mary200
Mary400
John200
John500

Операции как в Си =, +=, -=, *=, /=, %=, +, /, %, ++, --.
Сравнения чисел, если оба числа, иначе - строк <, <=, ==, !=, >=, >
Логические операции !, ||, &&
Операция "пробел" конкатенация.

Примеры awk-программ

awk '{print ($2, $3)}' f-awk

И.И. 1980
А.В. 1979
С.К. 1979
И.Х. 1970

awk '/е/ {print ($2, $3)}' f-awk

А.В. 1979
И.Х. 1970

awk '/е/ {print ($1, 2000 - $3)}' f-awk

Петров 21
Хведоров 30

awk '{ s = s + $4}END {print ("Суммарный возраст:" s) print ("Средний возраст:" s/NR)}' f-awk

Суммарный возраст:190
Средний возраст:47.5

awk '{ s += $4 }{\
     print("NR="NR, "NF="NF)}
     END{print ("FILENAME=" FILENAME)
     print ("Значение позиционной переменной" $4 "\"пусто\" после окончания просмотра)")
     print ("Суммарный возраст:" s)
     print ("Средний возраст:" s/NR)}' f-awk

NR=1 NF=4
NR=2 NF=4
NR=3 NF=4
NR=4 NF=4

FILENAME=f-awk
Значение позиционной переменной "пусто" (после окончания просмотра)
Суммарный возраст:190
Средний возраст:47.5

Селекторы

Здесь "селектор" следует понимать, как расширение понятия "шаблон", поскольку там где в структуре команды указан шаблон, в общем случае может стоять любой селектор.
Замечание. Открывающая скобка действия "{" должна быть в строке селектора.
В качестве селектора может быть:

  1. выражение;
  2. шаблон;
  3. их комбинация.

Соответствующие примеры:
  1. $3 != $4 && $3 > 1970
    $3 % 2 == 1
    $1=="Иванов" - кавычки, чтобы воспринималось, как строка.
  2. /ab/ отлично от /a b/, / ab/ и /ab /
    Nполя ^шаблон - по совпадению
    Nполя !^шаблон - по несовпадению

    awk '$3~0 {print} ' < f-awk
    echo
    awk '$3!~0 {print} ' < f-awk

    Иванов И.И. 1980 50
    Хведоров И.Х. 1970 60

    Петров А.В. 1979 40
    Сидоров С.К. 1979 40

  3. Шаблон может формировать множество образцов или указывать, в каком месте поля искать:
    /^a/         поле начинается с "a"
    /a$/         поле кончается "a"
    \+            экранирует оператор
    [abc]        любой из символов "a", "b" и "c"
    [a-р]        любой символ диапазона
    *               0 или больше вхождений регулярного выражения
    +              1 или больше вхождений регулярного выражения
    ?              0 или 1 вхождение регулярного выражения
    ab|cd       "ab" или "cd"

    awk ' $3~/(7[0-9])$/ {print} ' f-awk

    Петров А.В. 1979 40
    Сидоров С.К. 1979 40
    Хведоров И.Х. 1970 60

    То есть в третьем поле выделить 70-е годы (7 и еще одна цифра от конца поля).

Еще примеры

awk '$1=="Иванов" {print} ' f-awk

Иванов И.И. 1980 50

awk '$4/2==30 {print} ' f-awk

Хведоров И.Х. 1970 60

awk '$3 != $4 && $3 > 1970 {print} ' f-awk

Иванов И.И. 1980 50
Петров А.В. 1979 40
Сидоров С.К. 1979 40

awk '$1~/нов$/ {print} ' f-awk

Иванов И.И. 1980 50

awk '/^Ив|дор/ {print} ' f-awk

Иванов И.И. 1980 50
Сидоров С.К. 1979 40
Хведоров И.Х. 1970 60

awk '/1980/,/1979/ {print} ' f-awk

Иванов И.И. 1980 50
Петров А.В. 1979 40

Действия В awk возможны следующие действия:
  1. присваивания выражений;
  2. операторы управления;
  3. операторы вывода;
  4. встроенные функции.

Операторы управления
Простейшие операторы

Структурные операторы

Структурные операторы в значительной степени аналогичны соответствующим операторам Си. В последнем случае для каждого индекса выполняется блок. Текстовые индексы рассматриваются в лексикографическом порядке.

awk ' $4~/40/ {if($3<=1980) {print("Фамилия: " $1 )M["40"]++}}
     $4~/50/ {M["50"]++}
     END {for(i in M){print(" i =" i " M[" i "]=" M[i])}} ' f-awk

Фамилия: Петров
Фамилия: Сидоров
i =40 M[40]=2
i =50 M[50]=1

awk ' BEGIN {ORS = " "}{ for(k=NF; k>0; --k) {print $k}{print RS}} ' f-awk | sed 's/^ //'

50 1980 И.И. Иванов
40 1979 А.В. Петров
40 1979 С.К. Сидоров
60 1970 И.Х. Хведоров

Здесь, кроме изменения очередности полей в строке на противоположное (что делает цикл "for"), предварительно устанавливается выходной разделитель - пробел и весь результат предварительно выдается в одну строку, поэтому после обработки каждой строки выдается команда "print RS" для перевода выходной строки. Редактор "sed" подключен через конвейер, чтобы убрать возможные пробелы в начале строки. Существенная деталь.

Если запустить лишь базовую структуру

awk '{ for(k=NF; k>0; --k) {print $k}}' f-awk


то все поля исходной таблицы с изменениями порядка внутри прежних строк получим вытянутыми в один столбец переводом строки:
50
1980
И.И.
Иванов
40
1979
А.В.
Петров
40
1979
С.К.
Сидоров
60
1970
И.Х.
Хведоров

Однако, если поставим ";" сразу после условия, т.е. сделаем пустое тело цикла, за пределы которого вынесен "print $k"

awk '{ for(k=NF; k>0; --k); {print $k}}' f-awk


то получим исходную таблицу
Иванов И.И. 1980 50
Петров А.В. 1979 40 Сидоров С.К. 1979 40
Хведоров И.Х. 1970 60

поскольку "$k" после выхода из цикла будет иметь значение "0", а "$0" - соответсвует всей строке в качестве значения(!), то "print $k" будет после каждого цикла печатать полные строки.

Ввод и вывод данных
В общем случае в команде awk может быть указано несколько файлов. Напомним форматы вызова команды:

     awk [-Fc] 'prog.awk' [file ...]
     awk [-Fc] -f prog.awk [file ...]
     ^
Файлы обрабатываются последовательно в указанном порядке. Это можно использовать для "настройки" awk команды при обработке последующих файлов.

Пусть файл "f0" имеет вид:
60 Сидоров

А файл awk-программы "prim.awk" имеет вид:
# если просматривается файл "f0" присваиваются значения переменным w1 - Сидоров, w2 - 60
FILENAME == "f0" { w1 = $2; w2 = $1 }

# означенные переменные используются в селекторах
$1 == w1 { print ("фамилия: "$1)}
$4 == w2 { print ("годы: " $4)}

awk -f prim.awk f0 f-awk

фамилия: Сидоров
годы: 60

То есть второе поле файла "f0" дает значение переменной "w1", а первое - "w2". Эти переменные используются в селекторах при обработке файла "f-awk".
Изменим программу в файле "f-awk":
FILENAME == "f0" {w1 = $2; w2 = $1; next}
     { print ("фамилия: "$1); next}
     $4 == w2 { print ("годы: " $4)}

фамилия: Иванов
фамилия: Петров
фамилия: Сидоров
фамилия: Хведоров

Если исключить первый оператор "next", то в выходном файле появится дополнительно первая строка:
фамилия: 60
поскольку выбирается снова первое поле в певом файле ("f0"). Если исключить и второй "next", то в выходном файле появится дополнительно последняя строка:
годы: 60
которая ранее не выводилась, так как в предшествующий оператор " { print ("фамилия: "$1)}" заканчивал работу на ПОСЛЕДНЕЙ строке файла "f-awk", поэтому "next" пропускал последующую командную строку
$4 == w2 { print ("годы: " $4)}

И еще одна модификация в связи с вводом данных с терминала. Вызов команды будет:

awk -f prim.awk f0 f-awk


А файл "prim.awk" примет вид:
BEGIN { print ("Введите годы и фамилию: ")} FILENAME == "-" {
w1 = $2
w2 = $1
next
}
$1 == w1 { print ("фамилия: "$1); next}
$4 == w2 { print ("годы: " $4)}

Встроенные функции:

Поля разделяются по ".", выбираются строки у которых длина первого поля больше 8-ми, и их длина "length ($1)" печатается перед строкой "$0".

awk ' BEGIN {FS = "."; a=0} length ($1) > 8 {print (length ($1), $0); a++}
     END {print ("Найдено строк: " a)}' f-awk
9 Сидоров С.К. 1979 40
10 Хведоров И.Х. 1970 60
Найдено строк: 2

awk '{i=split($0, Name, ".");
     for (j=1; j<=i; j++)
     print ("Name[" j "]=" Name[j])
     }' f-awk
Name[1]=Иванов И
Name[2]=И
Name[3]= 1980 50
Name[1]=Петров А
Name[2]=В
Name[3]= 1979 40
Name[1]=Сидоров С
Name[2]=К
Name[3]= 1979 40
Name[1]=Хведоров И
Name[2]=Х
Name[3]= 1970 60

awk '{print (length)}' f-awk

22
22
22
22

Поскольку все строки были выровнены пробелами, а в длине строки учитываются все символы до конца строки.
awk '{printf "%7.2f %s\n", NR, $0}' f-awk
echo
awk '{printf "\t%s %s \n", NR, $0}' f-awk
1.00 Иванов И.И. 1980 50
2.00 Петров А.В. 1979 40
3.00 Сидоров С.К. 1979 40
4.00 Хведоров И.Х. 1970 60

1 Иванов И.И. 1980 50
2 Петров А.В. 1979 40
3 Сидоров С.К. 1979 40
4 Хведоров И.Х. 1970 60

Примеры использования Awk

Конструкцию, используемую для вывода строк соответствующих заданной маске:

awk '{if ($0 ~ /pattern/) print $0}'

можно сократить до:

awk '/pattern/'


Условие в awk может быть задано вне скобок, т.е. получаем:

awk '$0 ~ /pattern/ {print $0}'


По умолчанию, действия производятся со всей строкой, $0 можно не указывать:

awk '/pattern/ {print}'

print - является действием по умолчанию, его тоже можно не указывать.

awk '/pattern/'


Для вывода значения первого столбца строки, в которой присутствует маска LEGO:

awk '/LEGO/ {print $1}'

Для вывода значения первого столбца строки, во втором столбце которой присутствует маска LEGO:

awk '$2 ~ /LEGO/ {print $1}'

Для замены слова LIGO на LEGO и вывода только измененных строк можно использовать:

awk '{if(sub(/LIGO/,"LEGO")) {print}}'

Но если нужно обработать все строки (как sed 's/LIGO/LEGO/'), конструкцию можно упростить (1 - true для всех строк):

awk '{sub(/LIGO/, "LEGO")}1'


Вывести все строки, за исключением каждой шестой:

awk 'NR % 6'


Вывести строки, начиная с 6 (как tail -n +6 или sed '1,5d'):

awk 'NR > 5'


Вывести строки, в которых значение второго столбца равно foo:

awk '$2 == "foo"'


Вывести строки, в которых 6 и более столбцов:

awk 'NF >= 6'


Вывести строки, в которых есть слова foo и bar:

awk '/foo/ && /bar/'

Вывести строки, в которых есть слово foo, но нет bar:

awk '/foo/ && !/bar/'

Вывести строки, в которых есть слова foo или bar (как grep -e 'foo' -e 'bar'):

awk '/foo/ || /bar/'


Вывести все непустые строки:

awk 'NF'


Вывести все строки, удалив содержимое последнего столбца:

awk 'NF--'


Вывести номера строк перед содержимым:

awk '$0 = NR" "$0'


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

cat test.txt | head -n +1 | grep foo | sed 's/foo/bar/' | tr '[a-z]' '[A-Z]' | cut -d ' ' -f 2

аналогичной конструкцией на awk:

cat test.txt | awk 'NR>1 && /foo/{sub(/foo/,"bar"); print toupper($2)}'


Использование диапазонов.
Вывести группу строк, начиная со строки, в которой есть foo, и заканчивая строкой, в которой есть bar:

awk '/foo/,/bar/'


Исключив из вывода строки с вхождением заданных масок:

awk '/foo/,/bar/{if (!/foo/ && !/bar/)print}'

Более оптимальный вариант:

awk '/bar/{p=0};p;/foo/{p=1}'


Исключить только строку с завершающим вхождением (bar)

awk '/bar/{p=0} /foo/{p=1} p'


Исключить только строку с начальным вхождением (foo)

awk 'p; /bar/{p=0} /foo/{p=1}'


Разбиение файла по шаблонам.

Имеется файл (file), в котором группы строк разделены шаблонами FOO1,FOO2 и т.д. Необходимо записать данные, находящиеся между метками FOO в разные файлы, соответствующие указанным в FOO номерам.

awk -v n=1 '/^FOO[0-9]*/{close("out"n); n++; next} {print > "out"n}' file

В GNU Awk можно сделать так:

LC_ALL=C gawk -v RS='FOO[0-9]*\n' -v ORS='{print > "out"NR}' file


Парсинг CSV.

По умолчанию в качестве разделителя используются пробел и табуляция. Чтобы определить иной разделитель, например запятую, нужно использовать FS=',' или опцию "-F". В качестве параметра может быть задано регулярное выражение, например, FS='^ *| *, *| *$'.
Но для разбора CSV это не подойдет, так как пробелы могут присутствовать и внутри строк, поэтому проще вырезать лидирующие пробелы перед и после запятой:

FS=','
for(i=1;i<=NF;i++){
     gsub(/^ *| *$/,"",$i);
     print "Field " i " is " $i;
}

Если в CSV данные помещены в кавычки, например "field1","field2", то подойдет такой скрипт:
FS=','
for(i=1;i<=NF;i++){
     gsub(/^ *"|" *$/,"",$i);
     print "Field " i " is " $i;
}

Но скрипт придется усовершенствовать для разбора полей вида: field1, "field2,with,commas" , field3 , "field4,foo":
$0=$0",";
while($0) {
     match($0,/[^,]*,| *"[^"]*" *,/);
     sf=f=substr($0,RSTART,RLENGTH);
     gsub(/^ *"?|"? *,$/,"",f);
     print "Field " ++c " is " f;
     sub(sf,"");
}

Проверка IPv4 адреса.
awk -F '[.]' 'function ok(n) {
     return (n ~ /^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$/)
}
{exit (ok($1) && ok($2) && ok($3) && ok($4))}'

Сравнение двух файлов.
Вывод всех дублирующихся строк из двух неотсортированных файлах file1 и file2:

awk '!($0 in a) {c++;a[$0]} END {exit(c==NR/2?0:1)}' file1 file2


Вывод только выделенных блоков текста.
Например, чтобы показать из файла с текстом только текст, отмеченный как =текст= можно использовать:

awk -v RS='=' '!(NR%2)'

с форматированием переносов строк:

awk -v RS='=' '!(NR%2){gsub(/\n/," ");print}'


Сжатие в архив всех папок в директории.
Необходимо сжать все папки в директории /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 "$1)}'

Поиск строчек с определенным регулярным выражением:
#поиск строк содержащий " - " (пробел тире пробел)
echo "НАТАЛЬЯ СЕНЧУКОВА - СЛУЖЕБНЫЙ РОМАН" | awk '{if ($0 ~ /.+ - .+/) {print $0}}'
Пример поиска точного слова в определенном столбце и работу с числами:
#Поиск Фамилии (слова Иванов именно в первом столбце) и возраста старше 30 лет ( четвертый столбец)
echo "Иванов Иван Иванович 45 лет" | awk '{if (($1=="Иванов")&&($4>30)) print $0}'

Подсчет объема всех 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"%"}'

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"\"")}'

Поиск пакетов с удаленными файлами:
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 таблицы по времени создания файлов в директории:
# подсчитывает кол-во файлов в директории и всех вложенных папках созданных в октябре
# и формирует таблицу формата 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>"
# подсчитывает кол-во файлов в директории и всех вложенных папках созданных в октябре,
# причем файлы должны содержать текст "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>"

Подсчёт количества файлов в заданной директории:
echo $1
find $1 -type d -depth 1 | awk '{print $0; system("find \""$0"\" | /home/count1.sh")}'

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) |\
     netcat 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 недоступен!";

else print "Сервер r-info.net доступен!"}'
Не забудем указать полные пути для всех команд: awk, telnet, ...
Результатом работы скрипта будет письмо пользователю от которого был запущен скрипт.

Скрипт, который переворачивает файл (последняя строка станет первой и т.д.)

cat file.txt | awk 'BEGIN {FS="\n"; RS=""; OFS=""} {for (i=NF; i>0; i--) print $i;}'

В линуксе для этой цели есть утилита tac

Дублирование прав доступа.
Программисты прислали архив движка сайта, но права на все папки и файлы были неправильно установлены. для копирования прав используем скрипты:
Для начала установим права 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 - поиск файлов по правам доступа.
© Все права защищены 2011-2024