Как неловкий
Эта глава является учебником для начинающих, чтобы помочь Вам изучить, как использовать язык программирования 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.
Точки с запятой в конце оператора являются обычно дополнительными. (Они требуются, только если необходимо поместить больше чем один оператор на одну строку).
Новая строка (разрыв строки) заканчивает оператор. Во многом как сценарии оболочки или макросы препроцессора C при помещении наклонной черты влево в конце одной строки оператор продолжается на следующую строку.
Вместо того, чтобы иметь a
main
функция, основная часть кода разделена на ряд действий фильтра, окруженных изогнутыми фигурными скобками. Эти фильтры применяются последовательно для каждой записи во входном файле. Это означает, что код между изогнутыми фигурными скобками может выполниться несколько раз.Переменные - все в глобальной области видимости за исключением параметров к функциям. (Функциональные локальные переменные описаны больше в Функциях в AWK.)
Переменные поддерживают свое значение через многократные записи и файлы. Они установлены, пока явно не очищено.
В отличие от сценариев оболочки (но как 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 |
Необходимо заметить четыре вещи об этом сценарии:
Строки, разделенные пробелами, связываются автоматически, как они находятся в C.
print
оператор во многом какprint
оператор в Perl. (Язык AWK также поддерживаетprintf
, чей синтаксис походит на версию командной строки,printf
, за исключением того, что параметры разделяются запятыми вместо пробелов.)awk
интерпретатор всегда требует входного файла, даже если Ваш сценарий ничего фактически не читает из него. Если Вы хотитеawk
для чтения из стандартного ввода необходимо передать дефис (-
) как имя файла.awk
интерпретатор может взять или строку необработанного кода или файл для выполнения. Если Вы передаете в строке кода как первый параметр, тот код выполняется. Если Вы хотитеawk
для выполнения кода от файла необходимо передать-f
флаг, сопровождаемый путем файла сценария.
Условные правила фильтра в 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:
Массивы выделяются и растут динамично, поскольку необходимо пространство.
Массивы могут быть редкими; у Вас может быть массив со значением в индексе
711
и значение в индексе1116
ни с чем между ними.Вы не можете заполнить массив в единственной работе кроме путем разделения строки.
Существует два способа создать массив. Первое путем простого использования его. Второе при помощи 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
.
Например, этот сценарий делает следующее:
Отправляет две строки в
/bin/tail -n 1
.tail
инструмент распечатывает последнюю отправленную строку (который содержит вторую строку). Это демонстрирует, что первые два оператора печати оба отправили свой вывод в тот же экземплярtail
.Закрывает вывод к тому каналу и отправляет другое сообщение в хвост. Это показывает что новый экземпляр
tail
обработанный эта команда (потому что иначе, предыдущая строка не была бы распечатана).Записи две строки к файлу
/tmp/testfile-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 |
Другой полезный метод, когда контакт со сложными наборами результатов должен записать различные части данных к различным файлам. Парсинг нескольких простых файлов может иногда быть проще, чем парсинг единственного сложного набора результатов, особенно при парсинге его в сценарии оболочки.