Как неловкий

Эта глава является учебником для начинающих, чтобы помочь Вам изучить, как использовать язык программирования AWK и awk интерпретатор. awk интерпретатор, во многом как sed, grep, и perl, обычно используемый инструмент обработки текста на основе регулярных выражений.

Для более подробного ссылочного материала см. страницу руководства для awk, GNU руководство AWK (http://www .gnu.org/software/gawk/manual/), и книга Брайана Кернигана, Язык программирования AWK.

Эта глава использует файл poem.txt от Регулярных выражений, Освобожденных как основание для большинства его примеров. Обязательно создайте тот файл прежде, чем делать попытку любого из этих примеров.

Эти примеры тестируются прежде всего на версии OS X AWK, полученного из «Одной Истины AWK” Брайаном Керниганом. Сообщите о любых проблемах совместимости с другими версиями AWK с помощью ссылок на отзыв у основания каждой страницы.

Что такое AWK?

AWK является языком, разработанным прежде всего для обработки записей структурированных данных, содержащих текст. Этот язык выполняется awk интерпретатор.

Проект AWK центрируется вокруг деления входного текста в записи, каждый содержащий много полей. Каждый раз awk интерпретатор встречается с разделителем записей, он начинает новую запись. По умолчанию разделитель записей является символом новой строки, хотя можно изменить это, как описано в Изменении Разделителей записей и Разделителей полей в Сценариях AWK.

После awk интерпретатор считал полную запись из ввода, он делит ту запись на поля. Поля разграничены разделителем полей, подобным разделителям полей, описанным в Переменном Расширении и Разделителях полей.

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

Простой сценарий AWK

В его самом основном синтаксис сценария AWK очень подобен C. Существенные различия:

В отличие от сценариев оболочки (но как C), переменным в сценариях AWK не предшествуют знаки доллара при использовании их. Это означает, что они не могут быть вставлены посреди строк.

Существует несколько специальных переменных, которым предшествует знак доллара, как бы то ни было. Переменная $0 представляет все рекордное чтение от входного файла. Точно так же AWK делит каждую запись на поля, представленные специальными переменными начиная с $1 и нумерация вверх.

Вот простой сценарий AWK:

{
        a=$0;
        print "This is a test: a is " a;
}

Сохраните этот файл как 01_simple.awk, тогда выполните его путем ввода:

awk -f 01_simple.awk poem.txt

Это выполняет сценарий AWK 01_simple.awk и передает файл poem.txt как его ввод. Для каждой записи (одна строка, по умолчанию) в файле, это распечатает следующее:

This is a test: a is line from file

Необходимо заметить четыре вещи об этом сценарии:

Условные правила фильтра в AWK

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

Формат для условного правила фильтра следующие:

pattern { action }

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

Регулярные выражения в AWK

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

  • /mary/i— Нечувствительное к регистру соответствие для «Мэри» фактически распознает или слово «Мэри» или букву «я», который является, вероятно, не, что Вы хотите.

  • s/lamb//— Замены не позволяются здесь и вызовут синтаксическую ошибку.

Следующий сценарий AWK распечатает каждую строку, содержащую «ягненка».

/lamb/ {
        a=$0;
        print "This is a test: a is " a;
}

Сохраните этот файл как 02_conditional_regex.awk, тогда выполните его с помощью awk интерпретатор путем ввода:

awk -f 02_conditional_regex.awk poem.txt

Как с условными выражениями в C, можно объединить многократные регулярные выражения с булевыми операторами ! (не), || (или), и && (и). Например, соблюдающее правило ищет любую строку, содержащую «Мэри», но не содержащую ни «ягненка», ни «имевшую»:

/Mary/ && !(/lamb/ || /had/){
        a=$0;
        print "This is a test: a is " a;
}

Сохраните этот файл как 03_conditional_multiregex.awk, тогда выполните его путем ввода:

awk -f 03_conditional_multiregex.awk poem.txt

Это распечатывает следующий текст:

This is a test: a is and everywhere that Mary went,
This is a test: a is What about Mary, Mary, and Mary?

Для получения дополнительной информации о регулярных выражениях, считайте Освобожденные Регулярные выражения.

Диапазоны выражения в awk

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

Рассмотрите следующий awk сценарий:

/married/,/lowercase/{ print $0; }

Сохраните этот файл как 05_conditional_range.awk, тогда выполните его путем ввода:

awk -f 05_conditional_range.awk poem.txt

awk интерпретатор распечатывает каждую строку в файле стихотворения, начинающемся со строки, содержащей «женатый» и заканчивающейся строкой, содержащей «нижний регистр».

Выражения отношения в AWK

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

Сценарии AWK поддерживают четыре канонических формы выражения отношения:

  • выражение ~ /regexp/— Выражение соответствует регулярное выражение.

  • выражение !~ /regexp/— Выражение не соответствует регулярное выражение.

  • выражение comparison_operator выражение — Основная строка или числовое сравнение между двумя выражениями.

  • выражение in array_name — Выражение является ключом в указанном массиве. (См. Работу с Массивами в AWK для получения дополнительной информации о работе с массивами.)

comparison_operator может быть любым стандартом C операторы сравнения, такой как ==, !=, и т.д.

Выражение обычно является или одним из полей или результатом работы на одном из полей. Например, соблюдающие правила фильтра AWK показывают, соответственно, как сравнить первое поле с «Мэри» нечувствительным к регистру способом, как соответствовать все записи, не содержащие «Мэри», и как сделать точное сравнение первого поля против «Мэри»:

tolower($1) ~ /mary/ { print "CI Record: " $0; }
$0 !~ /Mary/ { print "Not Mary: " $0; }
$1 == "Mary" { print "Mary Record: " $0; }

Сохраните этот файл как 04_conditional_insensitive.awk, тогда выполните его с awk интерпретатор путем ввода:

awk -f 04_conditional_insensitive.awk poem.txt

Сценарий выводит серию строк, начинающихся со следующего:

CI Record: Mary had a little lamb,
Mary Record: Mary had a little lamb,
Not Mary: its fleece was white as snow,
Mary Record: Mary fleece was white as snow,
Mary Record: Mary everywhere that Mary went,

Специальные образцы в AWK: BEGIN и END

Сценарии AWK поддерживают два специальных образца:BEGIN и END.

Любое действие связалось с BEGIN образец выполняется, прежде чем первая запись читается из файла. Необходимо, например, внести любые изменения в разделители записей или разделителей полей в a BEGIN действие, как описано в Изменении Разделителей записей и Разделителей полей в Сценариях AWK.

Точно так же любое действие связалось с END образец выполняется после того, как последняя запись читается и обрабатывается. Вы могли использовать это для вывода специального конца записи данных, например.

Следующий пример показывает использование BEGIN и END образцы.

BEGIN { print "Here is the line we care about."; }
/chocolate/ { print "Mmm.  Chocolate.  " $0; }
END { print "That's all that matters."; }

Сохраните этот файл как 06_beginend.awk, тогда выполните его с awk интерпретатор путем ввода:

awk -f 06_beginend.awk poem.txt

Это распечатывает следующее:

Here is the line we care about.
Mmm.  Chocolate.  I want chocolate for Valentine's day.
That's all that matters.

Условное сопоставление с образцом с переменными

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

BEGIN { lastwasmary = 0; }
(tolower($1) ~ /mary/ && !lastwasmary) { print "Mary appeared."; lastwasmary = 1; }
(tolower($1) ~ /mary/ && lastwasmary) { print "Mary appeared again"; lastwasmary = 1; }
(tolower($1) !~ /mary/ && lastwasmary) { print "No Mary."; lastwasmary = 0; }

Этот сценарий распечатывает слова “Мэри, появившаяся” на первой строке, в которой «Мэри» является первым словом, но выполняет соответствие нечувствительным к регистру способом. Это распечатывает “Мэри, появившуюся снова” для каждой последовательной строки, в которой «Мэри» появляется как первое слово.

Если «Мэри» не появляется как первое слово в строке, оно не распечатывает “Мэри” и переменной lastwasmary сбрасывается для обнуления. Таким образом, в следующий раз, когда «Мэри» появляется после этого, это распечатывает “Мэри, появившуюся” вместо “Мэри, появившейся снова”.

Конечно, в данном случае, можно быть более обеспеченным conditionalizing образец с помощью if/then оператор, как описано в Проверяет Утверждения в AWK.

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

BEGIN { maryword = "mary"; keyword=maryword "lamb"; }
(tolower($1) ~ keyword) { print "Mary appeared."; }
(tolower($1) !~ keyword) { print "No mary."; }

Это ищет любую строку, в которой «marylamb» появляется как первое слово (в нечувствительном к регистру сравнении).

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

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

BEGIN { maryword = "mary"; }
(tolower($1) ~ maryword "lamb" ) { print "Mary appeared."; }
(tolower($1) !~ maryword "lamb" ) { print "No mary."; }

Этот код ведет себя тождественно к предыдущему примеру, но без промежуточного переменного присвоения.

Изменение разделителей записей и разделителей полей в сценариях AWK

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

Если Вы не делаете что-то особенно необычное, необходимо обычно изменять разделитель записей, прежде чем будет считана первая запись. Чтобы сделать это, Вы используете специальный образец BEGIN, как описано в Специальных Образцах в AWK: BEGIN и END.

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

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

BEGIN {RS="i"; FS=/r/}
{
        print "Record is: " $0;
        print "First field is " $1;
}

BEGIN правило фильтра оценено перед первой записью в файле, таким образом установив разделитель записей в букву «я» и разделитель полей к букве «r». Затем после того, как первая запись читается, второе правило фильтра оценено против нее на основе измененного разделителя записей.

Язык AWK также поддерживает отдельные выходные разделители и для записей и для полей. Выходной разделитель записей и переменные разделителя полей ORS и OFS, соответственно.

Выходной разделитель полей автоматически распечатан между полями каждый раз, когда Вы распечатываете значение $0 (“целая рекордная” переменная), и выходной разделитель записей так же распечатан в конце $0.

Проверьте утверждения в AWK

Проверьте утверждения в сценариях AWK, синтаксически почти идентичны C, проверяют утверждения.

Если Оператор

Как в C, if оператор похож на это:

if (expression) statement;

Так же, как в C, можно создать составные операторы путем обертывания их в изогнутые фигурные скобки. Например, если Вы хотите выполнить два оператора, когда данная запись содержит слово Мэри, Вы могли бы записать сценарий AWK, который похож на это:

{
        if ($0 ~ /Mary/) {
                print "Mary is in this line:";
                print $0;
        } else {
                print "NOMATCH: " $0;
        }
}

В то время как Оператор

while взгляды оператора точно так же, как if оператор. Например:

{
        i=4
        if ($0 ~ /Mary/) {
                while (i) {
                        print i ":" $0;
                        i--;
                }
        }
}

Как в C, можно пропустить остающийся код в организации a while цикл путем вызова continue функция.

Для оператора

for синтаксис оператора имеет аспекты и синтаксиса C и синтаксиса сценария оболочки. Форма языка C for оператор следующие:

for (pre_expression; while_expression; post_expression) statement

Этот оператор эквивалентен следующему:

pre_expression;
while (while_expression) {
                    statement;
                post_expression;
}

Первое выражение, выполняющееся прежде, чем войти while цикл, обычно инициализирует один или несколько итераторов цикла. Второе выражение тогда тестируется на истину. В то время как это - истина, оператор выполняется. После каждой итерации через цикл выполняется третье выражение. Это обычно постепенно увеличивает или постепенно уменьшает итератор цикла.

Как в C, можно пропустить остающийся код в организации a for цикл путем вызова continue функция.

Например, следующий код распечатывает каждую строку, соответствующую «Мэри» три раза. Они пронумерованы 1, 2, и 4. Это пропускает случай где i==2, и таким образом номер 3 никогда не распечатывается.

{
        if ($0 ~ /Mary/) {
                for (i=0; i<4; i++) {
                        if (i==2) continue;
                        print i+1 ":" $0;
                }
        }
}

Кроме того, AWK поддерживает подобное оболочке (действительно, подобный Perl) версия for цикл, в котором это действует как итератор массива. Итеративный синтаксис массива:

for (key_variable in array) statement

Этот синтаксис описан более подробно в Работе с Массивами в AWK.

Пропуск записей и файлов

В любой точке в Ваших правилах фильтра можно пропустить обработку всех остающихся правил (эффективно пропускающий к следующей записи) при помощи next оператор. Например:

if (i > 4) next;

Аналогично, в любое время, можно пропустить обработку остатка от входного файла при помощи nextfile оператор. Например:

if (i > 4) nextfile;

if синтаксис оператора описан в, Проверяют Утверждения в AWK.

Функции в AWK

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

function function_name(parameter1 [, parameter2, ...]) {
                    action
}

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

Например, эта функция берет два параметра, вычитает их, и затем добавляет одного (1):

function subtractAndAddOne(a, b, c) {
        c = 1
        return (a-b+c);
}
BEGIN {
        print subtractAndAddOne(3, 2);
}

Работа с массивами в AWK

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

Массивы в сценариях AWK ассоциативны. Это означает, что каждый элемент матрицы сохранен как пара ключ/значение, приводящая к трем существенным различиям когда по сравнению с C:

Существует два способа создать массив. Первое путем простого использования его. Второе при помощи split функция. Эти методы описаны в разделах, следующих, вместе с полезными подсказками о работе с массивами.

Основы массива

Следующий код создает и распечатывает вызванный массив my_array содержа значения «куропатка», «дерево», «груша» и «Кэссиди»:

BEGIN {
        my_array[0] = "Partridge";
        my_array[1] = "pear";
        my_array[2] = "tree";
        my_array["David"] = "Cassidy";
 
        for ( my_index in my_array ) {
                print my_index "=" my_array[my_index];
        }
}

Первая вещь, которую Вы заметите, состоит в том, что массив не распечатан в порядке. Фактически, это распечатано в порядке, в котором базовые данные хранятся внутренне. Если Вы хотите распечатать значения в ключевом порядке, необходимо идти через индекс численно вместо этого.

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

for (key_variable in array_name) statement

Третья вещь, которую Вы заметите, состоит в том, что, в отличие от C, элементы матрицы могут взять произвольные строки в качестве своего ключа (индекс массива). Если необходимо выполнить итерации через массив в ключевом порядке, однако, необходимо ограничить себя числовыми ключами.

Как побочный эффект, ключи всегда сохранены как строка, даже если они только содержат числа. Таким образом, если Вы хотите сравнить их численно друг с другом (например, для нахождения самого маленького ключа, для которого значение существует), необходимо добавить нуль (0) к ключу до того, чтобы делать сравнение.

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

BEGIN {
        my_array[0] = "Partridge";
        my_array[1] = "pear";
        my_array[2] = "tree";
        my_array[13] = "Cassidy";
 
        min = 0; max = 0;
        for ( my_index in my_array ) {
                if (my_index+0 < min) min = my_index;
                if (my_index+0 > max) max = my_index;
        }
        for (i=min; i<= max; i++) {
                if (i in my_array) {
                        print i "=" my_array[i];
                }
                if (!(i in my_array)) {
                        print i " is unset.";
                }
        }
}

В этом примере необходимо отметить if синтаксис оператора около конца. Прежде, чем распечатать значение массива, проверки в качестве примера, чтобы видеть, было ли значение когда-либо сохранено для того значения ключа:

if (i in my_array) { ... }

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

if (!(i in my_array)) { ... }

Создание Массивов с разделением

Присвоение элементов матрицы индивидуально может быть очень утомительным. Более общее (читает «менее болезненный») способ создать массив с split функция. split синтаксис следующие:

count = split( string, array_name, regexp );

Например, следующий код разделяет строку “морозильник ягненка Мэри” на слова, разделенные пробелами.

BEGIN {
        arr_len = split( "Mary lamb freezer", my_array, / / );
}

Результат - это arr_len содержит номер три (3). Переменная my_array[1] содержит «Мэри», my_array[2] содержит «ягненка», и т.д.

Копирование и присоединение к массиву

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

BEGIN {
        arr_len = split( "Mary lamb freezer", my_array, / / );
        for (word in my_array) {
                copy_array[word] = my_array[word];
        }
        for (word in copy_array) {
                print copy_array[word];
        }
}

Точно так же язык AWK не обеспечивает функции для присоединения к массиву. Для присоединения к массиву необходимо записать простую функцию как этот:

function join(input_array, separator) {
        string = "";
        first = 1;
 
        # Note: the array items are in no particular
        # order when joined with this function.
        for (i in input_array) {
                if (first) first = 0;
                else string = string separator;
                string = string input_array[i];
        }
        return string;
}
BEGIN {
        arr_len = split( "foo bar baz", my_array, / /);
 
        for (word in my_array) {
                print my_array[word];
        }
 
        print join(my_array, " ");
}

Как все функции массива записанное использование формы итератора массива for оператор, это соединение не происходит ни в каком определенном порядке. Если необходимо присоединиться к значениям массива в определенном порядке, необходимо записать собственное join функция или использование числового итератора или вручную указанный список полей. Например:

function count_elements(input_array)
{
    counter=0;
    for (word in input_array) {
        counter++;
    }
    return counter;
}
function join(input_array, separator) {
        string = "";
        first = 1;
 
        # Note: this preserves order, but does not
        # work with nonnumeric or sparse arrays.
        for (i=1; i<=count_elements(input_array); i++) {
                if (first) first = 0;
                else string = string separator;
                string = string input_array[i];
        }
        return string;
}
BEGIN {
        arr_len = split( "foo bar baz", my_array, / /);
 
        for (word in my_array) {
                print my_array[word];
        }
 
        print join(my_array, " ");
}

Удаление элементов матрицы

Как Вы видели в Основах Массива, Вы можете добавленные стоимости к массиву с помощью произвольных ключей. Можно также проверить, чтобы видеть, существует ли значение для данного ключа с помощью if (key in array) синтаксис.

Если необходимо удалить пару ключ/значение, Вы могли бы присвоить пустое значение. Однако if (key in array) синтаксис все еще оценивает к истине, потому что существует все еще значение для того ключа (хотя пустое значение). Таким образом Вы, вероятно, хотите удалить ключ полностью.

Язык программирования AWK решает эту проблему с delete функция. Синтаксис для delete :

delete array_name[key];

Например, следующий сценарий распечатывает только пары ключ/значение, “фиолетовые = куропатка” и “величества = дерево”.

BEGIN {
        my_array["purple"] = "Partridge";
        my_array["mountain"] = "pear";
        my_array["majesties"] = "tree";
        my_array["fruited"] = "Cassidy";
 
        mykey = "fruited";
        delete my_array["mountain"];
        delete my_array[mykey];
 
        for (i in my_array) {
                print i "=" my_array[i];
        }
}

Если необходимо очистить все значения от массива одновременно, тем не менее, Вы не должны удалять их по одному. Вместо этого можно просто сделать следующее:

delete array_name;

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

Ввод и вывод файла

Язык программирования AWK был прежде всего предназначен как фильтр между один или несколько входные файлы (или стандартный ввод) и стандартный вывод. Однако это действительно обеспечивает некоторую основную возможность ввода и вывода.

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

Кроме того, как в сценариях оболочки, любой оператор печати может быть передан по каналу к внешнему инструменту с помощью канала (|) оператор.

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

Например, этот сценарий делает следующее:

BEGIN {
        print "This is a test." | "/usr/bin/tail -n 1";
        print "This is only a test." | "/usr/bin/tail -n 1";
        close("/usr/bin/tail -n 1");
        print "Yikes!" | "/usr/bin/tail -n 1";
 
        print "This is another test" > "/tmp/testfile-awk"
        print "This is yet another test entirely" > "/tmp/testfile-awk"
}

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

Когда Вы вызываете getline, awk интерпретатор устанавливает переменную $0 к следующей записи от указанного файла. Функциональные возвраты 1 если запись была считана, 0 если конец файла был достигнут, или -1 если ошибка произошла (например, если файл не существует).

Следующий сценарий AWK читает запись из /tmp/testfile-awk, и затем читает запись из вывода echo команда:

BEGIN {
        getline < "/tmp/testfile-awk";
        print "The record was " $0;
 
        "/bin/echo 'This is a test line'" | getline
        print "The second record was " $0;
}

Интеграция сценариев AWK со сценариями оболочки

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

Принятие параметров от сценариев оболочки

Во многом как столь же именованные переменные C, ARGV переменная является массивом параметров, переданных сценарию AWK, и ARGC переменная содержит число параметров в ARGV. Эти переменные продемонстрированы в Перечислении 9-1.

  Сценарий тестирования перечисления 9-1 для параметров (23_arguments.awk)

{
    for (i=0; i<ARGC; i++) {
        print "ARGUMENT " i " is " ARGV[i];
    }
}

Сохраните этот сценарий как 23_arguments.awk и затем дайте следующие команды:

echo > myinputfile
awk -f 23_arguments.awk myinputfile

Необходимо видеть следующий вывод:

ARGUMENT 0 is awk
ARGUMENT 1 is myinputfile

Чтение переменных окружения

Как в сценариях оболочки, сценарии AWK имеют доступ к переменным окружения. Интерпретатор AWK хранит копию своей среды в ENVIRON ассоциативный массив, индексированный именем переменной.

Например, для печати значения PATH переменная окружения, Вы записали бы код как следующее:

{
    print "PATH IS: " ENVIRON["PATH"];
}

Извлечение вывода из сценариев AWK

При записи сценариев оболочки одна из самых хитрых вещей разобраться обрабатывает вывод инструментов, которые вызывают сценарии. К счастью, формат табличных данных, обычно используемый сценариями AWK, также просто считать в сценариях оболочки. Среда командной строки UNIX обеспечивает cut инструмент, который специально предназначен для извлечения табличных данных из строк текста.

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

BEGIN {
    RS="\n";
    FS="\t";
}
{
    print $1 "\t" $3 "\t" $5;
}

Можно проанализировать его вывод как показано в Перечислении 9-2.

Перечисление 9-2  , Анализирующее вывод сценария AWK

#!/bin/sh
 
# Store the output in a variable.
 
OUTPUT="$(awk 'BEGIN { \
        RS="\n"; \
        FS="\t"; \
     } \
     { \
        print $1 "\t" $3 "\t" $5; \
     }' tab_delimited_file)"
 
# Set the field separator to a newline so that
# the "for" statement below will put one line
# at a time in the "LINE" variable.
IFS="
"
 
# Parse and print the records.
RECORD=1
for LINE in $OUTPUT ; do
        # By default, cut uses tab as its delimiter,
        # so these commands take the first,
        # second, and third tab-delimited fields
        # from a single line of input, respectively.
        FIELD_1="$(echo "$LINE" | cut -f 1)"
        FIELD_2="$(echo "$LINE" | cut -f 2)"
        FIELD_3="$(echo "$LINE" | cut -f 3)"
 
        echo "RECORD $RECORD"
        echo "    FIELD 1: $FIELD_1"
        echo "    FIELD 2: $FIELD_2"
        echo "    FIELD 3: $FIELD_3"
        echo
        RECORD="$(expr $RECORD '+' 1)"
done

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