Awk примеры. Отбор строк из заданного диапазона. Отбор строк по условиям относительно отдельных слов

Текст это сердце Unix. Философия "все есть файл" полностью пронизывает всю систему и разработанные для нее инструменты. Вот почему работа
с текстом является одним из обязательных навыков системного администратора или начинающего пользователя Linux.

AWK - один из самых мощных инструментов для обработки и фильтрации текста, доступный даже для людей никак не связных с программированием.

Использование awk в Linux

Простейшая и часто востребованная задача - выборка полей из стандартного вывода. Вы не найдете более подходящего инструмента для решения этой задачи, чем awk. По умолчанию awk разделяет поля пробелами. Если вы хотите напечатать первое поле, вам нужно просто указать awk параметр $1:

echo "one two three four" | awk "{print $1}"

Да, использование фигурных скобок немного непривычно, но это только в первое время. Вы уже догадались как напечатать второе, третье, четвертое, или другие поля? Правильно это $2, $3, $4 соответственно.

echo "one two three four" | awk "{print $3}"

Иногда необходимо представить данные в определенном формате, например, выбрать несколько слов. AWK легко справляется с группировкой нескольких полей и даже позволяет включать статические данные:

echo "one two three four" | awk "{print $3,$1}"
three one

echo "one two three four" | awk "{print "foo:",$3,"| bar:",$1}"
foo: three | bar: one

Если поля разделены не пробелами, а другим разделителем, просто укажите в параметре -F нужный разделитель в ковычках, например ":" :

echo "one mississippi:two mississippi:three mississippi:four mississippi" | awk -F":" "{print $4}"
four mississippi

Но разделитель не обязательно заключать в ковычки. Следующий вывод аналогичен предыдущему:

echo "one mississippi:two mississippi:three mississippi:four mississippi" | awk -F: "{print $4}"
four mississippi

Иногда нужно обработать данные с неизвестным количеством полей. Если вам нужно выбрать последнее поле можно воспользоваться переменной $NF. Вот так вы можете вывести последнее поле:

echo "one two three four" | awk "{print $NF}"
four

Также вы можете использовать переменную $NF для получения предпоследнего поля:

echo "one two three four" | awk "{print $(NF-1)}"
three

Или поля с середины:

echo "one two three four" | awk "{print $((NF/2)+1)}"
three

echo "one two three four five" | awk "{print $((NF/2)+1)}"
three

Все это можно сделать с помощью таких утилит как sed, cut и grep но это будет намного сложнее.

И еще одна возможность awk, поддержка обработчиков для строк:

echo -e "one 1\n two 2" | awk "{print $1}"
one
two

echo -e "one 1\n two 2" | awk "{print $2}"
1
2

echo -e "one 1\n two 2" | awk "{sum+=$2} END {print sum}"
3

Это означает что мы должны выполнять следующий блок кода для каждой строки. Это можно использовать, например, для подсчета количества переданных данных по запросам из журнала веб-сервера.

Представьте себе, у нас есть журнал доступа, который выглядит так:

23 июля 18:57:12 HTTPD : "GET / Foo / бар HTTP / 1.1" 200 344
23 июля 18:57:13 HTTPD : "GET / HTTP / 1.1" 200 9300
23 июля 19:01:27 HTTPD : "GET / HTTP / 1.1" 200 9300
23 июля 19:01:55 HTTPD : "GET / Foo / Baz HTTP / 1.1" 200 6401
23 июля 19:02:31 HTTPD : "? GET / Foo / Baz страница = 2 HTTP / 1.1" 200 6312

Нам известно что последнее поле это число переданных байт, тогда мы можем использовать переменную $NF:

< requests.log awk "{print $NF}"
344
9300
9300

В этой статье мы покажем вам некоторые практические примеры того, как использовать AWK на .

Введение

AWK назван в честь фамилии его авторов: Альфред Ахо, Питер Вайнбергером и Брайан Керниган. AWK очень полезный язык сценариев для обработки текста. Этот язык выполняется в интерпретаторе. Это позволяет пользователю обрабатывать некоторые входные, определять переменные, использовать логические операторы, строки и числовые функции, извлечения данных и создания отформатированных отчетов. Синтаксис AWK очень близок с языку C и является прямым предшественником Perl. Все сценарии AWK могут быть преобразованы в сценарии Perl с использованием утилиты A2P.

Предпосылки

Интерпретатор AWK является стандартным инструментом, найденным на каждом дистрибутиве Linux. Пакет gawk содержит версию AWK с открытым исходным кодом, и в зависимости от дистрибутива Linux он может быть установлен из исходного файла или с помощью пакетов gawk или mawk, включенных в конкретный дистрибутив Linux.

Установка

С правами суперпользователя

Ssh root@IP_Address

Для того, чтобы установить утилиту командной строки AWK на /Fedora или на любую другую на основе RPM распределения Linux, выполните следующую команду:

Yum install gawk

В / , вам нужно вызвать эту команду, чтобы установить Gawk:

Apt-get install gawk

Примеры команды AWK

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

Вы можете использовать команду AWK для печати только определенных столбцов из поля ввода. Например, с помощью команды приведенной ниже вы можете узнать список IP-адресов, которые подключены к серверу:

Netstat -anp|grep tcp|awk "{print $5}"| cut -d: -f1 | sort | uniq -c | sort -n

Это очень полезно, если вы расследуете, находиться ли ваш сервер под атакой DoS или DDoS.

В следующем примере мы используем AWK для поиска конкретного шаблона в определенных столбцах и делаем какое-то действие, на основе результата:

Exim -bpr | grep frozen | awk {"print $3"} | xargs exim -Mrm

Выше команда удалит все замороженные сообщения электронной почты из почтовой очереди Exim.

AWK часто используется для выполнения полезной и практической обработки и манипуляции текста. Например, мы можем использовать AWK для удаления дубликатов в текстовом файле без сортировки:

Awk "!x[$0]++" file-with-duplicates > new-file-without-duplicates

Следующая команда напечатает пять случайных чисел от 0 до 999:

Awk "BEGIN { for (i = 1; i <= 5; i++) print int(1000 * rand()) }"

Используйте следующую команду, чтобы подсчитать количество строк в файле с именем «sample_file»:

Awk "END { print NR }" sample_file

Следующая команда выведет все строки в файле «sample_file», которые содержат строки, начинающиеся с ‘ A ‘ или ‘a’, за которыми следует ‘ re’:

Awk "/re/{print}" /opt/sample_file

Вы можете использовать команду AWK для более сложных операций. Если ваш веб-сайт работает довольно медленно, вы можете использовать следующую команду, чтобы проверить, есть ли какая-то проблема с диском I/O (и/или сети, в некоторых редких случаях):

Tac /proc/stat | awk "/^btime/ {up=systime()-$2;print "up " up/86400 "d"}; /^cpu / {print "user " $2/up "%, nice " $3/up "%, sys " $4/up "%, idle " $5/up "%, iowait " $6/up "%, steal " $9/up "%\niowait/used " $6 / ($2+$3+$4) ", steal/used " $9 / ($2+$3+$4) }"

IOWAIT означает, как долго процессы блокируются занятые вводом/выводом, в основном дискового хранения или, возможно, сети. STEAL означает, как долго процессы блокируются удачей CPU Time slice на сервере. Выше iowait на время процессора пользователя (=USER + NICE + SYSTEM) показывает занят ввода / вывода, выше украсть просматривается показывает занят CPU.

Следующий сценарий использует простую команду awk, которая выполняет поиск во входном файле ‘/etc/passwd ‘ и предоставляет вывод с именем пользователя, за которым следует дата и время последнего входа:

Vi login-check #!/bin/bash for user in `awk -F: "{print $1}" /etc/passwd` do echo -n "$user: " finger $user | grep Last if [ $? != 0 ]; then echo fi done

Сделайте скрипт исполняемым:

Chmod 755 login-check

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

./login-check

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

Вывод

Есть некоторые новые языки, такие как Perl и Python, которые могут быть использованы вместо AWK, но использование AWK имеет ряд преимуществ, так как:

  • AWK очень легко узнать.
  • AWK может быть использован для решения определенных типов задач быстрее и создавать более эффективные сценарии, чем при использовании других инструментов/языков.
  • AWK очень удобен при работе с большими файлами, как журналы и т.д., потому что с помощью команды/скрипа AWK вы можете создать отфильтрованный и удобочитаемый отчет.

04.10.2015
16:55

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

Способы запуска awk-программ

Если awk -программа достаточно простая и короткая, то ее код можно набрать прямо в консоли:

Awk "< код awk-программы >" < имя_файла_для_обработки >

В качестве входных данных для awk можно использовать не только текстовые файлы, но и вывод в стандартный поток других приложений:

< некое_приложение > | awk "< код awk-программы >"

В случае, когда код awk -программы достаточно объемный или должен быть сохранен для повторного использования, его можно вызывать из файла с ключом -f:

Awk -f < имя_файла_с_кодом_awk_программы > < имя_файла_для_обработки >

Для проведения экспериментов используем файл test.cpp , на котором будем проверять результаты работы awk - программ:

#include #include #include void test1(); int test2(); // Комментарий в стиле С для функции main() int main(int argc, char** argv) { std::cout << "Hello, world!" << std::endl; for(int i = 0; i < 10; ++i) { std::cout << i << std::endl; } return 0; } // Комментарий в стиле С для функции test1() void test1() { std::cout << "Hello, test1!" << std::endl; } // Комментарий в стиле С для функции test2() int test2() { std::cout << "Hello, test2!" << std::endl; }

Реклама

Фильтрация строк с помощью awk

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

Отбор строк, соответствующих регулярному выражению

Например, чтобы получить все строки файла test.cpp , содержащие директиву препроцессора #include , воспользуемся следующей командой:

Awk "/^#\s*include/" test.cpp

Регулярное выражение записывается между двумя символами / . В результате получим:

#include #include #include

Отбор строк, НЕ соответствующих регулярному выражению

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

Awk "! /^[/]{2}.*/" test.cpp

Вот что осталось:

#include #include #include void test1(); int test2(); int main(int argc, char** argv) { std::cout << "Hello, world!" << std::endl; for(int i = 0; i < 10; ++i) { std::cout << i << std::endl; } return 0; } void test1() { std::cout << "Hello, test1!" << std::endl; } int test2() { std::cout << "Hello, test2!" << std::endl; }

Отбор строк из заданного диапазона

Определить диапазон строк для вывода на экран можно с помощью двух регулярных выражений, записанных через запятую. В качестве примера найдем определение всех функций, возвращающих int:

Awk "/^int .*(.*) {/, /^}/" test.cpp

Соответствующий результат:

Int main(int argc, char** argv) { std::cout << "Hello, world!" << std::endl; for(int i = 0; i < 10; ++i) { std::cout << i << std::endl; } return 0; } int test2() { std::cout << "Hello, test2!" << std::endl; }

Комбинирование условий фильтрации

Для проверки строк сразу по нескольким условиям используйте операторы && (И) и || (ИЛИ) .

Следующая команда выводит все комментарии, которые не содержат main:

Awk "/[/]{2}.*/ && ! /main/" test.cpp

В итоге имеем:

// Комментарий в стиле С для функции test1() // Комментарий в стиле С для функции test2()

Ранее мы искали диапазон строк по двум регулярным выражениям, но если номера строк, которые нужно вывести, известные заранее, то все упрощается:

Awk "4 < NR && NR < 7" test.cpp

NR - переменная awk , которая определяет номер строки. Таким образом, представленный код выводит 5-ую и 6-ую строки:

Void test1(); int test2();

Отбор строк по условиям относительно отдельных слов

Awk может фильтровать текст не только по строкам, но и по отдельным словам. На i -ое слово в строке можно сослаться с помощью $i . Нумерация начинается с единицы, а $0 определяет содержимое всей строки. Количество слов в строке определяется с помощью переменной NF , поэтому $NF указывает на последнее слово. Например, найдем строки, первым словом которых является int или void:

Awk "$1 == "int" || $1 == "void"" test.cpp

Соответствующий вывод на консоль:

Void test1(); int test2(); int main(int argc, char** argv) { void test1() { int test2() {

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

Awk "$1 ~ /int|void/" test.cpp

Отбор строк на основе числовых характеристик

В awk доступны арифметические операторы языка C, что открывает свободу действий. Пример ниже выводит все четные строки (NR - номер строки):

Awk "NR % 2 == 0" test.cpp

Соответствующий вывод:

#include int test2(); // Комментарий в стиле С для функции main() std::cout << "Hello, world!" << std::endl; for(int i = 0; i < 10; ++i) { } return 0; void test1() { } // Комментарий в стиле С для функции test2() std::cout << "Hello, test2!" << std::endl;

Следующая awk -программа выводит все строки, у которых длина 1-ого слова равна трем:

Awk "length($1) == 3" test.cpp

В результате получаем:

Int test2(); int main(int argc, char** argv) { int test2() {

Awk "NF == 2" test.cpp

И соответствующий вывод:

#include #include #include void test1(); int test2(); return 0;

Реклама

Работа со строками в awk

Как вы могли убедиться, awk обладает неплохим набором функций для фильтрации строк текста. Однако для этих строк еще можно выполнять различные преобразования. Команды для работы со строками должны быть обернуты в фигурные скобки { ... } . Код в скобках последовательно вызывается для каждой строки обрабатываемого текста.

Форматированный вывод

В awk имеется прямой аналог функции printf() языка C . В качестве примера выведем в начале каждой строки ее номер:

Awk "{ printf "%-2d %s\n", NR, $0 }" test.cpp

Вот что получили:

1 #include 2 #include 3 #include 4 5 void test1(); 6 int test2(); 7 8 // Комментарий в стиле С для функции main() 9 int main(int argc, char** argv) { 10 std::cout << "Hello, world!" << std::endl; 11 12 for(int i = 0; i < 10; ++i) { 13 std::cout << i << std::endl; 14 } 15 16 return 0; 17 } 18 19 // Комментарий в стиле С для функции test1() 20 void test1() { 21 std::cout << "Hello, test1!" << std::endl; 22 } 23 24 // Комментарий в стиле С для функции test2() 25 int test2() { 26 std::cout << "Hello, test2!" << std::endl; 27 }

Функции преобразования

Кроме printf() есть в awk и другие функции. Например, print() и toupper() :

Awk "{ print toupper($0) }" test.cpp

Соответствующий результат:

#INCLUDE #INCLUDE #INCLUDE VOID TEST1(); INT TEST2(); // КОММЕНТАРИЙ В СТИЛЕ С ДЛЯ ФУНКЦИИ MAIN() INT MAIN(INT ARGC, CHAR** ARGV) { STD::COUT << "HELLO, WORLD!" << STD::ENDL; FOR(INT I = 0; I < 10; ++I) { STD::COUT << I << STD::ENDL; } RETURN 0; } // КОММЕНТАРИЙ В СТИЛЕ С ДЛЯ ФУНКЦИИ TEST1() VOID TEST1() { STD::COUT << "HELLO, TEST1!" << STD::ENDL; } // КОММЕНТАРИЙ В СТИЛЕ С ДЛЯ ФУНКЦИИ TEST2() INT TEST2() { STD::COUT << "HELLO, TEST2!" << STD::ENDL; }

Условные конструкции

В awk -программах доступны операторы if-else . Например, следующий код выводит без изменения строки, у которых на 1-ой позиции стоит int , а на последней - { , иначе на консоль отправляется --- :

Awk " { if($1 == "int" && $NF == "{") print; else print "---" }" test.cpp

Выполнение кода приводит к выводу следующего:

Int main(int argc, char** argv) { --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- int test2() { --- ---

Переменные

Доступны в awk -программах и переменные, которые не требуется предварительно объявлять. Следующий код для подсчета количества строк и слов в тексте поместим в файл stat.awk:

{ lineCount++; wordCount += NF } END { printf "line count: %d, word count: %d\n", lineCount, wordCount }

Тогда его вызов осуществляется следующим образом:

Awk -f stat.awk test.cpp

Результат выполнения:

Line count: 27, word count: 88

Фильтр END указывает, что код в скобках после него должен выполняться только после прохода всех строк. Доступен в awk и фильтр BEGIN , поэтому в более общем случае программа принимает вид:

BEGIN { Вызывается до начала прохода по строкам } { Вызывается для каждой строки после секции BEGIN, но до секции END } END { Вызывается после завершения прохода по строкам }

Wc -lw test.cpp

Циклы

В awk -программах вам также доступны циклы for и while в стиле C . Для примера выведем все строки в обратном порядке. Создадим файл reverse.awk следующего содержимого:

{ for(i = NF; i > 0; --i) printf "%s ", $i; printf "\n" }

Вызовем программу следующий образом:

Awk -f reverse.awk test.cpp

В результате слова в каждой строке будут выведены в обратном порядке:

#include #include #include test1(); void test2(); int main() функции для С стиле в Комментарий // {) argv char** argc, int main(int std::endl; << world!" "Hello, << std::cout {) ++i 10; < i 0; = i int for(std::endl; << i << std::cout } 0; return } test1() функции для С стиле в Комментарий // { test1() void std::endl; << test1!" "Hello, << std::cout } test2() функции для С стиле в Комментарий // { test2() int std::endl; << test2!" "Hello, << std::cout }

Нестандартный разделитель слов

По умолчанию awk в качестве разделителя слов использует пробельные символы, однако такое поведение можно изменить. Для этого воспользуйтесь ключом -F , после которого укажите строку, определяющую разделитель. Например, следующая программа выводит название группы и ее пользователей (если в группе есть пользователи) из файла /etc/group , применяя в качестве разделителя символ двоеточия:

Awk -F":" "{ if($4) printf "%15s: %s\n", $1, $4 }" /etc/group

Комбинирование фильтров и команд печати

Все рассмотренные ранее фильтры можно использовать совместно с командами обработки строк. Достаточно записать ограничения перед фигурными скобками. Ниже представлен пример для вывода первых 9 строк вывода команды ps , содержащей информацию о пользователе, идентификаторе процесса и имени команды:

Ps axu | awk "NR < 10 { print $1, $2, $NF }"

После запуска увидим:

USER PID COMMAND root 1 /sbin/init root 2 root 3 root 5 root 7 root 8 root 9 root 10

В статье я планирую делиться полезными примерами, которые помогают мне решать повседневные задачи и значительно упрощают использование командной строки. Для тех, кто ещё не знаком с AWK, рекомендую обязательно освоить этот скриптовый язык, сложного в нем ничего нет. Каждый пример я планирую сопровождать небольшими комментариями, проливающими свет на нюансы использования тех или иных операторов.
.

Ищем строку с параметром bind-address в конфигурационном файле.

root@debian:~# awk ‘/bind-address/’ /etc/mysql/my.cnf
bind-address = 127.0.0.1
bind-address = 192.168.1.110

Пояснения: AWK имеет следующий синтаксис и опции.

awk [-f файл_программы | ‘программа’] [-Fразделитель]
[-v переменная=значение] [файл …]

−F value — определяет разделитель (устанавливает значение встроенной переменно FS);
−f file — текст программы считывается из файла, вместо командной линии. Поддерживается чтение из множества файлов;
−v var=value — присвоение переменной необходимого значения;
−− — обозначает окончания списка опций.

Пример №2

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

root@debian-wordpress:~# cat /etc/mysql/my.cnf | awk ‘/bind-address/’
bind-address = 127.0.0.1
bind-address = 192.168.1.110

Как можно увидеть, результат вывода остался точно таким же, хотя конструкция конечно же усложнилась. Надо сказать в этом примере не совсем целесообразно использовать второй вариант, поскольку он сложнее. Попробуем рассмотреть другие ситуации, где использование подобной конструкции будет оправдано.

Пример №3

Вывести список символьных ссылок и путей к конечным файлам.

root@debian:~# ls -l /bin/ | awk ‘/lrwxrwxrwx/ { print $9, $10, $11}’
bzcmp -> bzdiff
bzegrep -> bzgrep
bzfgrep -> bzgrep
bzless -> bzmore
lessfile -> lesspipe
lsmod -> kmod
mt -> /etc/alternatives/mt
nc -> /etc/alternatives/nc
netcat -> /etc/alternatives/netcat
open -> openvt
pidof -> /sbin/killall5
rbash -> bash
rnano -> nano
sh -> dash
sh.distrib -> dash

Пояснения: программа awk представляет из себя пару шаблона (pattern ) и действия ({ action } ), а также определений пользовательских функций. Шаблон и действие имеют следующий вид: шаблон { действие } Шаблон либо действие может быть опущено. В первом случае действие будет выполняться к каждой строке, во втором будет осуществляться обычный вывод на экран, эквивалентный команде { print } . Эти ключевые слова нельзя сочетать с другими шаблонами .

Входная строка обычно состоит из полей, разделенных пробельными символами. (Эту настройку по умолчанию можно изменить с помощью встроенной переменной FS или опции -F разделитель .) Поля обозначаются $1, $2, …; $0 ссылается на всю строку в целом.

Пример №4

Исходя из информации выше, рассмотрим пример с изменением разделителя по умолчанию — просмотреть список всех пользователей без дополнительной информации.

root@debian:~# awk -F «:» ‘{ print $1 }’ /etc/passwd
root
daemon
bin
sys
sync
games
man

(Вывод команды сокращен)

Пояснения: поскольку в файле /etc/passwd записи хранятся в виде «root:x:0:0:root:/root:/bin/bash «, вполне логично разделителем выбрать двоеточие и вывести самое первое поле ($1 ) каждой строки ($0 ).

Пример №5

Все в том же файле с пользователями можно посчитать их количество.

root@debian:~# awk ‘END { print NR }’ /etc/passwd
25

Пояснения: Специальные шаблоны BEGIN и END можно использовать для получения управления перед чтением первой входной строки и после прочтения последней входной строки, соответственно.

AWK(1)

НАЗВАНИЕ
awk - сопоставление с шаблонами и преобразование текста

СИНТАКСИС

Awk [-Fсимвол] [[-f] программа] [аргумент...] [файл...]

ОПИСАНИЕ
Команда awk сопоставляет строки исходных файлов с шаблонами, определенными в программе. Шаблоны можно задать либо непосредственно в командной строке, либо поместить в файл с именем программа и воспользоваться опцией -f. Если шаблоны указаны в командной строке, их следует заключить в одинарные кавычки ("), чтобы избежать интерпретации shell"ом.

Команде awk могут быть переданы аргументы в виде x=... y=... и т.д. (см. ПРИМЕРЫ).

Файлы читаются в том порядке, как они заданы. Если не указано ни одного файла или задано имя -, используется стандартный ввод. Ввод для awk делится на записи, разделяемые специальным символом. По умолчанию это перевод строки; в таком случае awk обрабатывает ввод построчно. Разделитель записей можно изменить, переопределив переменную RS. Каждая запись делится на поля, ограниченные разделителями полей (по умолчанию - пробелами). Этот разделитель можно изменить, переопределив переменную FS или указав флаг -Fсимвол. Поля исходных строк доступны по именам $1, $2,...; $0 - вся входная строка.

Для каждого шаблона из программы может быть задано действие, которое будет произведено со всякой строкой, успешно сопоставленной с шаблоном. Оператор шаблон-действие имеет вид:

Шаблон { действие } Каждая исходная строка сопоставляется с каждым из шаблонов; в случае успеха выполняются указанные действия. После сопоставления со всеми шаблонами вводится следующая строка и процесс сопоставления повторяется. Может быть опущен либо шаблон, либо действие, но не оба вместе. Если для данного шаблона не указаны действия, то строка просто копируется на стандартный вывод. Если для действия не определен шаблон, то оно будет выполняться для каждой входной строки. Строки, которые не удалось сопоставить ни одному шаблону, игнорируются.

Действие есть последовательность операторов. Так как шаблоны и действия могут быть опущены, то, чтобы различать их в программе, последние надо брать в фигурные скобки. Оператор есть одна из конструкций:

If (условие) оператор [ else оператор ] while (условие) оператор for (выражение; условие; выражение) оператор break continue { [ оператор ] ... } переменная = выражение print [ список_выражений ] [> выражение ] printf формат [, список_выражений ] [> выражение ] next # пропустить оставшиеся шаблоны и перейти к следующей строке exit # пропустить оставшиеся строки

Операторы завершаются точкой с запятой, переводом строки или правой скобкой. Пустой список_выражений означает всю строку. Выражения строятся из цепочек символов и чисел с помощью операций +, -, *, /, % и конкатенации (обозначается пробелом). В выражениях также можно использовать операции из языка C: ++, --, +=, -=, *=, /=, %=. Переменные инициализируются пустыми цепочками. Переменные могут быть скалярами, элементами массива (обозначается x[i]) или полями. Индексами массива могут служить любые (не обязательно числовые) цепочки символов, что позволяет реализовать разновидность ассоциативной памяти. Цепочки символов заключаются в двойные кавычки (").

Оператор print выдает свои аргументы на стандартный вывод (или в файл, если присутствует часть >выражение), разделяя их текущим разделителем полей и завершая каждую запись выходным разделителем записей. Оператор printf делает то же самое, но под управлением формата [см. printf(3S) ].

Встроенная функция length возвращает длину своего аргумента, рассматривая его как цепочку символов; если аргумент опущен, то возвращается длина текущей строки. Определены также следующие встроенные функции: exp, log, sqrt и int (int отбрасывает дробную часть своего аргумента). Функция substr(s, m, n) возвращает n-символьную подцепочку цепочки s, начинающуюся с позиции m. Функция sprintf(формат, выражение, выражение,...) преобразует выражения в соответствии с указанным форматом [см. printf(3S) ] и возвращает полученную цепочку символов.

Шаблон - это произвольная логическая комбинация, составленная с помощью операций!, ||, && и скобок из регулярных выражений и выражений сравнения. Регулярные выражения обрамляются символами / [подробнее см. egrep(1) ]. Отдельное регулярное выражение в шаблоне сопоставляется со всей строкой. Регулярные выражения могут входить и в выражения сравнения. Шаблон может состоять из двух шаблонов, разделенных запятой; при этом указанные действия выполняются для всех строк между строкой, удовлетворяющей первому шаблону, и строкой, удовлетворяющей второму шаблону.

Выражение сравнения - это одна из следующих конструкций:

Выражение опер_сопост регулярное_выражение выражение опер_сравн выражение

где опер_сравн - любая из шести операций сравнения языка C, опер_сопост это ~ (содержится) или!~ (не содержится).

Условие - это арифметическое выражение, выражение сравнения или их логическая комбинация.

Для выполнения каких-либо действий перед первой или после последней строки определены специальные шаблоны BEGIN и END. BEGIN должен быть первым шаблоном, END - последним. Например, для использования символа c в качестве разделителя полей можно либо запустить программу с опцией -Fc, либо указать

BEGIN { FS = c } Остальные специальные переменные: NF Количество полей в текущей записи. NR Порядковый номер текущей записи. FILENAME Имя файла, из которого в данный момент производится ввод. OFS Разделитель полей при выводе, по умолчанию пробел. ORS Разделитель записей при выводе, по умолчанию перевод строки. OFMT Формат вывода чисел, по умолчанию %.6g.

ПРИМЕРЫ

  1. Вывести строки файла f1, содержащие более 72 символов: awk "length > 72" f1
  2. Вывести первые два поля файла f2 в обратном порядке: awk "{ print $2, $1 }" f2
  3. Сложить числа, стоящие в первом столбце файла f3, вывести сумму и среднее арифметическое:
    В файле prog: { s += $1 } END { print "sum is", s, " average is", s/NR } Командная строка: awk -f prog f3
  4. Вывести поля файла f4 в обратном порядке: awk "{ for (i = NF; i > 0; --i) print $i }" f4
  5. Вывести все строки файла f5, находящиеся между парами start/stop awk "/start/,/stop/" f5
  6. Вывести те строки файла f6, у которых первое поле не совпадает с первым полем предыдущей строки: awk "$1 != prev { print; prev = $1 }" f6
  7. Распечатать файл f7, вставляя после слова "Page" номер страниц, начиная с пятой:
    В файле prog: /Page/ { $2 = n++ } { print } Командная строка: awk -f prog n=5 f7

СМ. ТАКЖЕ
egrep(1) , lex(1) , sed(1) .
printf(3S) в Справочнике программиста.

СЮРПРИЗЫ
Входные пробелы не сохраняются при выводе, если поля этой записи подвергались изменениям.

В языке команды awk отсутствуют явные преобразования между цепочками символов и числами. Чтобы выражение трактовалось как число, прибавьте к нему 0; чтобы трактовалось как цепочка - сконкатенируйте его с пустой цепочкой ""




Top