AWK — это специализированный скриптовый язык программирования, изначально разработанный в конце 1970-х годов в среде операционной системы Unix. Главным предназначением языка является сканирование, потоковая обработка и фильтрация структурированных текстовых данных. Будучи одной из классических командно-строковых утилит, язык оказал значительное влияние на развитие системного администрирования и автоматизации рутинных задач по обработке текстов.

Общие сведения и архитектура

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

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

История создания

Первоначальная версия языка была разработана в 1977 году для операционной системы Unix V7. В создании инструмента принимал участие Брайан Керниган, один из соавторов языка C, что наложило заметный отпечаток на синтаксис и базовые функции AWK. В 1985 году была выпущена существенно переработанная версия языка, а в 1988 году опубликована книга, закрепившая окончательный стандарт описания.

Впоследствии инструмент развивался в рамках экосистемы Unix и Linux как бесплатное и открытое программное обеспечение. На сегодняшний день существует множество различных реализаций интерпретатора, наиболее известной из которых является GNU awk (gawk). Также созданы многочисленные трансляторы и конвертеры, позволяющие переводить код AWK на такие языки, как Java, C и Lisp.

Синтаксис и парадигмы программирования

Парадигма программирования в AWK строится вокруг фундаментального принципа «условие — действие». Каждая считанная интерпретатором запись проверяется на соответствие заданному логическому условию. Если условие выполняется истинно, к записи применяется определенное действие.

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

Для обращения к данным язык использует встроенные переменные. Доступ к полям текущей записи осуществляется через переменные, обозначаемые символом доллара и порядковым номером: $1, $2, $3 и так далее, где $1 — это первое поле записи. Переменная $0 содержит текущую запись целиком. При этом явное объявление переменных в языке не требуется, что существенно ускоряет процесс написания скриптов.

Помимо полей, язык предоставляет ряд встроенных системных переменных, значительно облегчающих парсинг: NF — количество полей в текущей записи; NR — порядковый номер текущей записи (счетчик строк); FILENAME — имя обрабатываемого файла; FS — символ-разделитель полей; RS — символ-разделитель записей.

В языке присутствуют средства процедурного программирования. Разработчику доступны циклы, условные ветвления и возможность объявления пользовательских функций, синтаксис которых во многом заимствован из языка C. Конкатенация строк в AWK осуществляется неявно: если две строковые константы или переменные расположены в коде рядом без дополнительных операторов, они автоматически объединяются в одну строку. Вывод данных чаще всего реализуется с помощью встроенной команды print, которая может печатать как отдельные поля, так и результаты математических вычислений.

Примеры кода

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

Пример скрипта для подсчета общего количества слов и символов во входном тексте:

 {
  слов += NF
  символов += length($0) + 1
 }

В данном случае условие отсутствует, поэтому блок кода в фигурных скобках выполняется для каждой строки. К переменной «слов» прибавляется количество полей (NF) в текущей строке, а к переменной «символов» — длина всей строки (length($0)) плюс один символ, учитывающий перевод каретки.

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

 BEGIN { FS = "[^a-zA-Z]+" }
 {
   цикл по всем полям записи
     массив[текущее_слово]++
 }
 END { печать результатов частотности }

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

Преимущества и недостатки

К главным преимуществам AWK относится возможность написания крайне коротких и понятных программ для манипуляций с текстом. Язык идеально подходит для работы с уже структурированными данными (таблицами, отчетами, лог-файлами) и способен выполнять сложный поиск с помощью мощного аппарата регулярных выражений. Инструмент глубоко интегрирован в операционные системы семейства Linux/Unix и отлично взаимодействует с другими утилитами, такими как grep или sort. Более того, при выполнении узкоспециализированных задач потоковой обработки текстов, AWK демонстрирует высокую производительность, опережая по скорости работы универсальные скриптовые языки, такие как Python или Perl.

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

См. также

Delphi Brainfuck

Смотреть видео