]]> ]]>
Править | Обсудить | История

AWK

Дата создания:
1977
Создан под влиянием:
Повлиял на:
Парадигма:
Типизация:
Принятые расширения файлов:
.awk
Реализации и версии (свернуть все | развернуть все):
Язык программирования

AWK (название происходит от первых букв фамилий авторов) — интерпретируемый скриптовый язык программирования, предназначенный для обработки текстовых данных.

AWK был создан в Bell Labs в 1977 году тремя авторами: Альфредом Ахо (Alfred Aho), Питером Вайнбергером (Peter Weinberger) и Брайаном Керниганом (Brian Kernighan). Эта версия языка вошла в Unix V7, выпущенный в 1979 году. В 1988 была выпущена книга “The AWK Programming Language”, в которой описывался новый диалект языка, вошедший в Unix SysV. Новый диалект был несовместим с исходным, и во избежание путанницы его называют nawk, или new awk, в то время как диалект 1977 года называют oawk, или old awk. nawk был выпущен под свободной лицензией в 1996 году и до сих пор поддерживается Керниганом.

В настоящее время AWK является одной из необходимых принадлежностей Unix-систем: вместе с Unix shell та или иная реализация AWK входит в стандартную поставку практически каждой Unix-подобной системы. Реализации AWK существуют для всех платформ.

Программа, написанная на AWK, принимает на вход поток текстовых данных (получаемых из файла или с консоли) и обрабатывает его построчно. Сама программа является набором правил вида “шаблон — действие”, где шаблон является регулярным выражением, а действие — последовательностью команд. Кроме того, программа может содержать определение пользовательских функций.

При обработке входного потока каждая строка данных сравнивается с каждым шаблоном, и выполняются действия тех правил, под шаблоны которых эта строка подходит. Шаблоны бывают следующих видов:

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

AWK позволяет обрабатывать каждую строку как целую строку (переменная $0) или как последовательность “полей” — подстрок, разделенных пробелами (переменные $1, $2, ...). Кроме этих встроенных переменных, доступен ряд других — количество прочитанных строк в файле NR, количество полей в текущей записи NF и т.д. Системные переменные позволяют настраивать режим обработки данных, например, задавать разделители записей и полей записи (по умолчанию — перенос строки и пробел).

AWK — динамически типизированный язык: все примитивные данные хранятся как строки, хотя могут обрабатываться как числа в зависимости от контекста их использования (например, в арифметических выражениях). Основная структура данных языка — ассоциативный массив с индексами-строками.

Среди недостатков языка называют:

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

Элементы синтаксиса:

Комментарий до конца строки #
Регистрозависимость да
Регулярное выражение идентификатора переменной [_a-zA-Z][_a-zA-Z0-9]*
Присваивание значения переменной varname = value
Объявление переменной нет
Объявление переменной с присваиванием значения нет
Группировка выражений ( ... )
Блок { ... }
Равенство a == b
Неравенство a != b
Определение функции function functionName(argname1, ..., argnameN)
Вызов функции functionName(arg1, ..., argN)
Вызов функции без параметров f()
Последовательность ; или конец строки
Если - то if (condition) trueBlock
Если - то - иначе if (condition) trueBlock else falseBlock
Цикл с предусловием while (condition) loopBody
Цикл с постусловием do loopBody while (!c)
Цикл for - next для диапазона целых чисел с инкрементом на 1 for (i = first; i <= last; i++) loopBody
Цикл for - next для диапазона целых чисел с декрементом на 1 for (i = last; i >= first; i--) loopBody

Примеры:

Hello, World!:

Пример для версий Jawk 1.02, gawk 3.1.6, mawk 1.3.3

Печать выполняется шаблоном BEGIN, т.е. перед обработкой входных данных. Сами данные не обрабатываются.

BEGIN { print "Hello, World!" }

Факториал:

Пример для версий Jawk 1.02, gawk 3.1.6, mawk 1.3.3

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

BEGIN {
    f = 1
    print "0! = " f
    for (i=1; i<17; i++) {
        f *= i
        print i "! = " f
    }
}

Числа Фибоначчи:

Пример для версий Jawk 1.02, gawk 3.1.6, mawk 1.3.3

Используется итеративное определение чисел Фибоначчи. fib — ассоциативный массив, pr — строка.

BEGIN {
    fib[1] = 1
    fib[2] = 1
    for (i=3; i<17; i++)
        fib[i] = fib[i-1]+fib[i-2]
    pr = ""
    for (i=1; i<17; i++)
        pr = pr fib[i] ", "
    print pr "..." 
}

Квадратное уравнение:

Пример для версий Jawk 1.02, gawk 3.1.6, mawk 1.3.3
{   A = $1
    B = $2
    C = $3
    if (A == 0) 
        print "Not a quadratic equation"
    else
    {   D = B*B-4*A*C
        if (D == 0)
            print "x = " (-B/2/A)
        else if (D > 0)
        {   print "x1 = " ((-B+sqrt(D))/2/A)
            print "x2 = " ((-B-sqrt(D))/2/A)
        }
        else
        {   print "x1 = (" (-B/2/A) "," (sqrt(-D)/2/A) ")"
            print "x2 = (" (-B/2/A) "," (-sqrt(-D)/2/A) ")"
        }
    }
}

CamelCase:

Пример для версий gawk 3.1.6

В переменной $0 хранится вся прочитанная запись-строка (в отличие от переменных $1, $2, …, в которых хранятся поля этой записи). Функция split разбивает строку text на фрагменты, разделенные строками, каждая из которых соответствует регулярному выражению, и записывает их в массив words. После этого каждый элемент words переводится в правильный регистр по частям функциями substr, toupper и tolower.

{   text = $0;
    split(text, words, /[^a-zA-Z]+/);
    for (i=1; i<=length(words); i++) {
        res = res toupper(substr(words[i],1,1)) tolower(substr(words[i],2));
    }
    print res
}

CamelCase:

Пример для версий Jawk 1.02, gawk 3.1.6, mawk 1.3.3

В реализации mawk нет функции length для определения количества элементов массива. В реализации Jawk ее также нельзя использовать — возникает ошибка “Cannot evaluate an unindexed array.”.

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

{   text = $0;
    N = split(text, words, /[^a-zA-Z]+/);
    for (i=1; i<=N; i++) {
        res = res toupper(substr(words[i],1,1)) tolower(substr(words[i],2));
    }
    print res
}

Комментарии

]]>

blog comments powered by Disqus

]]>

Работа программистам