Руководство пользователя для GNU Awk

Arnold D. Robbins
перевод Балуева А. Н.

12. Встроенные функции

Оглавление

Встроенные функции всегда доступны ля вызова из awk-программы. Эта глава определяет все встроенные функции в awk; некоторые из них упоминаются в других разделах, но здесь для удобства собраны все функции. (Можно также самостоятельно определять новые функции . См. главу 13 [Функции, определенные пользователем], стр. 153.)

12.1 Вызов встроенных функций

В начало страницы

Чтобы вызвать встроенную функцию, напишите ее имя и после него ее аргументы в скобках. Например, `atan2(y + z, 1)' есть вызов функции atan2 с двумя аргументами.

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

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

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

i = 4 j = sqrt(i++)

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

Например,

i = 5 j = atan2(i++, i *= 2)

Если порядок вычисления есть слева направо, то i сначала становится 6, а затем 12, и atan2 вызывается с двумя аргументами 6 и 12. А если порядок вычисления будет справа налево, i сначала будет 10, а потом 11 и atan2 будет вызван с двумя аргументами 11 и 10.

12.2 Численные встроенные функции

В начало страницы

Приведем полный список встроенных функций, работающих с числами. Необязательные параметры заключены в квадратные скобки ("[" and "]").

int(x)

Выдает ближайшее целое к x, расположенное между x и нулем, округленное в сторону нуля.

Например, int(3) есть3, int(3.9) есть 3, int(-3.9) есть \Gamma 3, and int(-3) есть то же самое \Gamma 3. sqrt(x)

Выдает положительный квадратный корень из x. Сообщает об ошибке, если x отрицателен. Так, sqrt(4) есть два.

exp(x)

Выдает экспоненту от x (e ^ x), или сообщение об ошибке, если x выходит за допустимые пределы, которые могут зависеть от представления чисел с плавающей точкой в вашей машине.

log(x)

Выдает натуральный логарифм x, если x положителен; в противном случае сообщает об ошибке.

sin(x)
Выдает синус от х, х в радианах.
cos(x)
Выдает косинус от  x, в радианах.
atan2(y, x)
Выдает арктангенс от  y / x в радианах.
rand()

Выдает случайное число. Значения rand равномерно распределены между нулем и единицей. Значение никогда не равно ни 0 ни 1. Иногда нужны случайные целые числа. Для этого имеется пользовательская функция для получения случайных неотрицательных целых меньших чем n:

function randint(n) -
return int(n * rand()) ""

Произведение дает случайные числа между 0 и n. Затем они превращаются в целые ( с помощью int) между нулем и n \Gamma 1, включительно. Приведем пример, где подобная функция используется для получения случайных целых между 1 и n. Эта программа печатает новое случайное число для каждой входной записи.

awk ' # Функция roll бросает модельную игральную кость.
function roll(n) - return 1 + int(rand() * n) ""

# Roll 3 бросает шестигранную кость и
# печатает  общее число точек. -
printf("%d points"n",
roll(6)+roll(6)+roll(6)) ""'

НИМАНИЕ: В большинстве реализаций awk, включая gawk, rand начинает генерировать числа с того же начального номера при каждом запуске awk. Таким образом, программа будет генерировать те же самые результаты при каждом ее запуске. Числа случайны в пределах одного запуска awk, но повторяются от запуска к запуску. Это удобно при отладке. Но если вы хотите, чтобы программа давала разные результаты при каждом запуске, нужно менять начальный номер в каждом прогоне. Для этого можно использовать srand.

srand([x])

Функция устанавливает начальный номер x для генерируемых случайных целых чисел. Каждое такое значение приводит к своей последовательности случайных чисел.1 Так, если вы во второй раз подставите то же начальное значение, вы опять получите точно ту же последовательность. Если опустить аргумент (вызвав srand()), то для получения начального номера будут использованы текущие дата и время. Это путь для получения чисел, которые на самом деле непредсказуемы. srand возвращает значение начального номера предыдущего запуска awk. Это позволяет следить за начальными номерами для согласования получаемых случайных последовательностей.

12.3 Встроенные функции для действий с цепочками

В начало страницы

Функции этого раздела просматривают или изменяют текст одной или более цепочек. Необязательные параметры заключены в квадратные скобки.

index(in, find)

Ищет в цепочке in первое вхождение цепочки find и возвращает номер символа в цепочке in, с которого начинается это вхождение. Например:

$ awk 'BEGIN - print index("peanut", "an") ""'
a 3
ПРИМЕЧАНИЕ 1

Генерируемые компьютером случайные числа не являются вполне случайными. Они технически известны как "псевдослучайные." Это значит, что хотя числа в последовательности кажутся случайными, можно фактически генерировать ту же самую последовательность снова и снова. Если цепочка find не обнаружена, функция index выдает ноль. (Вспомним, что позиции в цепочке awk нумерует с единицы.)

length([string])

Выдает количество символов в цепочке string. Если string есть число, то выдается длина цифровой цепочки, представляющей это число. Например, length("abcde") есть пять. В отличие от этого, length(15 * 35) вырабатывает три. Почему? Но 15 * 35 = 525, а 525 конвертируется в цепочку "525", которая содержит три символа! Если аргумент не указан, length выдает длину $0. В старых версиях можно было вызывать функцию length без всяких скобок. Это "резко осуждается" в стандарте POSIX. Что означает, что такая возможность будет удалена со временем из будущих версий стандарта. Поэтому, для максимальной переносимости ваших программ, нужно всегда употреблять скобки.

match(string, regexp)

Функция match ищет в цепочке string самую длинную, самую левую подцепочку, соответствующую регулярному выражению regexp. Она возвращает номер позиции начала найденной подцепочки (один, если она начинается в начале string). Если соответствия не найдено, возвращается ноль. Функция match устанавливает номер найденной позицию в встроенную переменную RSTART. Она также устанавливает в встроенную переменную RLENGTH длину упомянутой подцепочки. Если таковая не обнаружена, RSTART и RLENGTH получают значения ноль \Gamma 1.

Например:

awk '-
if ($1 == "FIND")
regex = $2 else -
where = match($0, regex) if (where != 0)
print "Match of", regex, "found at", "
where, "in", $0 "" ""'

Это программа разыскивает строки, которые соответствуют регулярному выражению, присвоенному переменной regex. Это регулярное выражение может меняться. Если первое слово в строке есть `FIND', regex заменяется вторым словом этой строки. Поэтому, если дано :

FIND ru+n
My program runs
but not very quickly
FIND Melvin JF+KM
This line is property of Reality Engineering Co.
Melvin was here.

awk напечатает:

Match of ru+n found at 12 in My program runs
Match of Melvin found at 1 in Melvin was here.

split(string, array [, fieldsep])

Эта функция разделяет string на куски, разделенные цепочками fieldsep, и записывает куски в массив array. Первый кусок запоминается в array[1], второй в array[2], и т.д. Строковое значение третьего аргумента fieldsep есть regexp, указывающее, где расщеплять строку (как FS может быть regexp для разделения входных записей). Если fieldsep опущено, используется значение FS. split возвращает количество созданных элементов.

Функция split расщепляет цепочки на куски подобно тому как входные строки расщепляются на поля. Например, split("cul-de-sac", a, "-") расщепляет цепочку `cul-de-sac' на три поля, используя `-' как сепаратор. Она устанавливает содержимое массива следующим образом: a[1] = "cul" a[2] = "de" a[3] = "sac" Этот вызов возвращает значение три. Как и в случае разделения входных полей, если значение fieldsep есть " ", начальные и конечные whitespace игнорируются и элементы разделяются группами whitespace. Также как с разделением входных полей, если fieldsep есть пустая цепочка, каждый отдельный символ цепочки поступает в отдельный элемент массива. (Это есть специальное расширение gawk.) Недавние реализации awk, включая gawk, допускают в качестве третьего аргумента как константу regexp (/abc/), так и цепочку (d.c.). Стандарт POSIX также допускает это. До расщепления цепочки split вычеркивает все ранее существующие элементы массива array (d.c.). Если цепочка не соответствует fieldsep совсем, array будет иметь один элемент. Его значением будет исходная цепочка.

sprintf(format, expression1,...)
Эта функция возвращает (без печати) ту цепочку, которую напечатала бы функция
printf c теми же аргументами (см. раздел 6.5 [Использование оператора
printf для декоративной печати], стр. 64). Например:
sprintf("pi = %.2f (approx.)", 22/7) возвращает цепочку
"pi = 3.14 (approx.)".
sub(regexp, replacement [, target])

Функция sub изменяет значение target. Она ищет в target, рассматриваемой как цепочка, самую левую самую длинную подцепочку, соответствующую регулярному выражению regexp, распространяя поиск как можно дальше. Затем в цепочке target найденный текст заменяется на replacement и модифицированная цепочка становится новым значением target.

Эта функция --- особенная, потому что target используется не только для вычисления значения и не должна быть выражением, а только переменной, полем или элементом массива, чтобы записать туда измененное значение. Если этот аргумент опущен, по умолчанию используется и изменяется $0. Например, str = "water, water, everywhere" sub(/at/, "ith", str) меняет значение str на "wither, water, everywhere", заменяя самое левое и самое длинное вхождение `at' на `ith'. Функция sub возвращает количество сделанных подстановок (один или ноль).

Если replacement содержит специальный символ `&', он представляет точную подцепочку, соответствующую regexp. (Если regexp может соответствовать более чем одной цепочке, то эта точная подцепочка может изменяться).

Например:

awk '- sub(/candidate/, "& and his wife"); print ""'

заменяет первое вхождение `candidate' на `candidate and his wife'
в каждой входной строке. А вот другой пример:

awk 'BEGIN -
str = "daabaaa" sub(/a*/, "c&c", str) print str ""'
a dcaacbaaa

Здесь показано, как `&' может представлять непостоянные цепочки, а также иллюстрируется правило "самая левая самая длинная" в соответствии regexp (см. раздел 4.6 [Как много текста соответствует?], стр.34). Эффект от этого специального символа (`&') может быть исключен помещением перед ним в цепочке обратного слеш. Как обычно, чтобы вставить один обратный слеш в цепочку, нужно написать два подряд. Поэтому пишите `""&' в строковой константе для включения литерала `&' в replacement. Например, покажем, как заменить первый `--' в каждой строке с `&':

awk '- sub(/"--/, """&"); print ""'

Заметьте: как говорилось выше, третий аргумент sub должен быть переменной, полем или ссылкой на массив. Некоторые версии awk допускают в качестве третьего аргумента выражение, которое не является lvalue. В таких случаях sub будет искать образец и возвращать ноль или один, но результат подстановки (если будет) отбрасывается. Такие версии awk принимают выражения вида, подобного следующему: sub(/USA/, "United States", "the USA and Canada") Для исторической совместимости gawk допускает подобные коды. Однако, использование всяких других неизменяемых объектов в качестве третьего параметра приводит к фатальной ошибке и программа не исполняется.

Наконец, если regexp не есть константа regexp, оно превращается в цепочку, которая используется как regexp для соответствия.

gsub(regexp, replacement [, target])

Действует подобно sub, но заменяет все длиннейшие левые не перекрывающиеся соответствующие подцепочки, которые может найти. `g' в gsub означает "global," т.е. заменять повсюду.

Например:

awk '- gsub(/Britain/, "United Kingdom"); print ""' заменяет все вхождения цепочки `Britain' на `United Kingdom' во всех входных записях. Функция gsub возвращает число сделанных подстановок. Если переменная для поиска и замены, target, опущена, то используется вся входная запись $0. Как и в sub, символы `&' and `"' имеют специальный смысл и третий аргумент должен быть lvalue.

gensub(regexp, replacement, how [, target])

gensub есть общая функция подстановки. Подобно sub и gsub, она ищет в цепочке target подцепочку, соответствующую регулярному выражению regexp. В отличие от sub и gsub, модифицированная цепочка возвращается как результат функции, а оригинальная цепочка target не меняется. Если how есть цепочка, начинающаяся с `g' или `G', то gensub замещает все соответствия regexp на replacement. В противном случае how есть число, указывающее, какое соответствие regexp заменить. Если target отсутствует, вместо нее используется $0.

gensub имеет дополнительное свойство, отсутствующее в sub и gsub: возможность указывать компоненты regexp в тексте для замещения. Это делается с помощью скобок в regexp для отметки компонент и затем указанием `"n' в замещающем тексте, где n есть цифра от 1 до 9.

Например:

$ gawk ' ? BEGIN - ? a = "abc def" ?
b = gensub(/(.+) (.+)/, """2 ""1", "g", a) ? print b ? ""'
a def abc

Как сказано выше для sub, вы должны написать два обратных слеша для того чтобы вставить один в цепочку. В замещающем тексте последовательность `"0' представляет целый соответствующий текст, как это делает символ `&'. Следующий пример показывает, как можно использовать третий аргумент для указания, какое соответствие regexp должно быть заменено:

$ echo a b c a b c -- ? gawk '- print gensub(/a/, "AA", 2) ""'
a a b c AA b c

В этом случае по умолчанию $0 используется в качестве цепочки target. gensub возвращает новую цепочку как свой результат, который передается непосредственно в print для печати.

Если аргумент how есть цепочка, которая не начинается с `g' или `G', или если это число меньшее нуля, то производится только одна подстановка. Если regexp не соответствует target, то gensub возвращает исходное, не измененное значение target.

gensub есть расширение gawk; она недоступна в режиме совместимости (см. раздел 14.1 [Параметры командной строки], стр. 161).

substr(string, start [, length])

Возвращает подцепочку длины length цепочки string, начинающуюся с символа с номером start. Первый символ string имеет номер один.

Например, substr("washington", 5, 3) возвращает "ing".

Если length отсутствует, эта функция возвращает хвост цепочки string, который начинается с символа номер start. Например, substr("washington", 5) возвращает "ington". Весь хвост возвращается также, если length больше длины хвоста.

ЗАМЕЧАНИЕ: цепочке, возвращаемой substr, нельзя ничего присваивать. Так, будет ошибкой пытаться изменить часть цепочки подобно следующему:

string = "abcdef"
# попытка получить  "abCDEf" не сработает:
substr(string, 3, 3) = "CDE"

или использовать  substr как третий аргумент в sub или gsub:

gsub(/xyz/, "pdq", substr($0, 5, 20)) # WRONG
tolower(string)

Возвращает копию цепочки, в которой буквы верхнего регистра заменены на соответствующие буквы нижнего. Небуквенные символы не меняются. Например, tolower("MiXeD cAsE 123") вернет "mixed case 123".

toupper(string)

Возвращает копию цепочки, в которой буквы нижнего регистра заменены на соответствующие буквы верхнего регистра. Остальные символы не меняются. Например, toupper("MiXeD cAsE 123") возвратит "MIXED CASE 123".

Дополнительные сведения о `"' и `&' в sub, gsub и gensub

При использовании sub, gsub или gensub, стараясь получить литералы обратных слешей и амперсантов в замещающем тексте, необходимо помнить, что имеется несколько уровней обработки управляющих последовательностей.

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

Затем следует уровень исполнения, когда awk фактически просматривает заменяющую цепочку и определяет, что генерировать.

На обоих уровнях awk ищет определенное множество символов, которые могут идти за обратным слешем. На лексическом уровне он ищет управляющие последовательности, перечисленные в разделе 4.2 [Управляющие последовательности], стр. 24. Так, для каждого `"' который awk будет обрабатывать на уровне исполнения, вы печатаете два `"' для лексического уровня. Когда символ, который не может быть в управляющей последовательности, следует за `"', Unix awk и gawk оба просто удаляют начальный `"'и кладут следующий символ в цепочку. Так, например, "a"qb" трактуется как "aqb".

На уровне исполнения различные функции обрабатывают последовательности из `"' и `&' различным образом. Ситуация, к несчастью, довольно сложная. Исторически функции sub и gsub рассматривают двух символьные последовательности `"&' специально; эта последовательность была заменена в генерированном тексте одним `&'. Все другие `"' в пределах замещающей цепочки, которые не предшествовали символу `&', были переданы без изменения.


Проиллюстрируем это таблицей:

Вы печатаете    sub видит        sub генерирует

"&                &            the matched text
""&              "&              a literal `&'
"""&             "&              a literal `&'
""""&           ""&              a literal `"&'
"""""&          ""&              a literal `"&'
""""""&        """&              a literal `""&'
""q              "q              a literal `"q'

Эта таблица показывает оба уровня: лексический уровень обработки, где нечетное количество обратных слешей становится четным для уровня исполнения , и обработку на уровне исполнения, проделываемую функцией sub. (Для упрощения следующие таблицы показывают только случай четного количества `"', обрабатываемых на лексическом уровне.)

Проблема с историческим подходом состоит в том, что нет способа получить литерал `"', за которым следует соответствующий образцу текст. Стандарт POSIX 1992 пытался разрешить эту проблему. Стандарт говорит, что sub and gsub ищут либо `"' либо `&' после `"'. Если какой-нибудь из них следует за `"', то этот символ выдается буквально. Интерпретация `"' `&' тогда становится такой:

Вы печатаете             sub видит            sub генерирует

   &                         &                the matched text
""&                         "&                 literal `&'
""""&                      ""&            literal `"', then the matched text
""""""&                   """&              a literal `"&'

Кажется, что проблема решена. К несчастью, слова в стандарте неясны. Он говорит фактически, что `"' отключает специальный смысл всех следующих символов, но это только для отличных от `"' и `&'. Такой специальный смысл непонятен. Такое определение приводит к двум проблемам.

1. Обратные слеши должны теперь дублироваться в цепочке замещения, что разрушает исторические программы awk.

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

2 Стандарт POSIX пересматривается.

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

Вы печатаете                sub видит               sub генерирует

""""""&                     """&                    a literal `"&'
""""&                       ""&       literal `"', followed by the matched text
""&                         "&                       literal `&'
""q                          "q                     literal `"q'

Короче, на уровне выполнения теперь имеются три специальные последовательности символов, `"""&', `""&' и `"&', в то время как исторически была только одна. Однако, как и в историческом случае, любой `"' , который не есть часть одной из упомянутых трех последовательностей, не является специальным и появляется в выходе буквально.

gawk 3.0 следует этим предложенным правилам POSIX для sub и gsub. Будут ли эти предложенные правила введены в стандарт, в настоящее время не известно. Последующие выпуски gawk будут следовать стандарту и реализовать указания окончательной его версии; также будет изменена и соответствующая часть этой книги.

Правила для gensub значительно проще. На уровне исполнения, всякий раз когда gawk видит `"', если следующий символ есть цифра, то текст, который соответствует заключенному в скобки подвыражению, идет в генерируемый выход. В противном случае, независимо от следующего символа, этот символ идет в генерируемый текст, а `"' не идет.

Вы печатаете                 gensub видит            gensub генерирует

&                             &                       the matched text
""&                          "&                       literal `&'
""""                         ""                       literal `"'
""""&                        ""&                literal `"', then the matched text
""""""&                     """&                      literal `"&'
""q                          "q                       literal `q'

Вследствие сложности обработки на лексическом и исполнительном уровнях и специальных случаев для sub и gsub, мы рекомендуем использовать gawk и gensub, когда нужно сделать подстановки.


2 Это следствие было определенно непреднамеренным.

3 Как в апреле 1999, с окончательным санкционированием и публикацией где-то в in 1997.

12.4 Встроенные функции для ввода\вывода

В начало страницы

Следующие ниже функции относятся к вводу\выводу (I/O). Необязательные параметры заключены в квадратные скобки ("[" и "]").

close(filename)

Закрывает файл filename для ввода и вывода. Альтернативным аргументом может быть команда оболочки, которая использовалась для перенаправления к или от конвейера; тогда конвейер закрывается. См. раздел 6.8 [Закрытие входных и выходных файлов и конвейеров], стр. 74.

fflush([filename])

Подавить любое связанное с буферным выводом имя, которое есть или файл, открытый для записи или команда оболочки для перенаправления вывода в конвейер. Многие служебные программы буферизуют свой вывод; в нем хранится информация для записи на дисковый файл или терминал в памяти до тех пор пока не наберется достаточная порция для посылки на выходное устройство. Часто это более эффективно чем запись каждого бита при его появлении. Однако, иногда необходимо подтолкнуть программу освободить ее буфера, то есть записать по ее назначению даже если буфер еще не полон. Для этого функция fflush и предназначена. gawk тоже буферизует свой вывод, и функция fflush может использоваться для освобождения ее буферов.

fflush представляет недавнее (1994) добавление к Bell Labs research версии awk; она не входит в стандарт POSIX и недоступна, если в командной строке было набрано `--posix' (см. раздел 14.1 [Параметры командной строки], стр. 161).

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

system(command)

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

END -
system("date -- mail -s 'awk run done' root") ""

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

Заметим, что перенаправление print или printf в конвейер часто достаточно для завершения вашей задачи. Если нужно выполнить несколько команд, будет более эффективным просто напечатать их в конвейер к оболочке:

while (что нужно сделать)
print command -- "/bin/sh" close("/bin/sh")

Однако если ваша awk-программа интерактивна, system полезна для запуска больших самостоятельных программ, таких как оболочка или редактор. Некоторые операционные системы не могут реализовывать системные функции. В таких случаях system приводит к фатальной ошибке.

Интерактивные vs . Неинтеракивная буферизация

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

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

$ awk '- print $1 + $2 ""' 1 1
a 2 2 3
a 5 Control-d

Каждая строка вывода печатается немедленно. Сравните это поведение со
следующим примером.

$ awk '- print $1 + $2 ""' -- cat 1 1 2 3 Control-d
_____________________________
4  Программа интерактивна, если стандартный вывод связан с терминалом.

a 2
a 5

Здесь никакого вывода не печатается, пока не будет выдан Control-d, поскольку он весь буферизован и послан по конвейеру к cat одной порцией.

Управление выходной буферизацией с помощью функции system

Функция flush осуществляет явное управление выходной буферизацией для отдельных файлов и конвейеров. Но их использование не переносится на многие другие реализации awk. Альтернативный метод очистки выходных буферов состоит в использовании system с пустой цепочкой в качестве аргумента:

system("") # flush output

gawk трактует такое употребление функции system как специальное действие и достаточно ловок, чтобы не выполнять оболочку (или другой интерпретатор команд) с пустой командой. Поэтому для gawk эта идиома не только полезна, но и эффективна. Если этот метод будет работать с другими реализациями awk, можно не стремиться избегать не необходимого вызова оболочки. (Другие реализации могут только освобождать буфер, связанный со стандартным выводом, а не весь буферизованный вывод.)

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

BEGIN -
print "first print" system("echo system echo") print "second print" ""

должна напечатать

first print system echo second print

а не

system echo first print second print

Если awk не очистила (flush) свои буфера до вызова system, вы увидите последний (нежелательный) вывод.

12.5 Функции для действий с отметками времени

В начало страницы

Обычное назначение awk-программ состоит в обработке регистрационных файлов с информацией о времени выдачи некоторых записей. Многие регистрационные программы записывают отметки времени в формате службы времени, который содержит число секунд, истекших после определенного момента. В системах POSIX это число секунд после полночи на 1 Января 1970, UTC. Чтобы облегчить обработку таких файлов и выдавать удобные отчеты, gawk предлагает две функции для работы с метками времени. Они обе представляют расширение gawk; их нет ни в стандарте POSIX, ни в других известных версиях awk. Необязательные параметры заключены в квадратные скобки ("[" and "]").

systime()

Эта функция возвращает текущее время как число секунд с системного момента. В системах POSIX это --- число секунд с полуночи 1 Января 1970, UTC. Оно может отличаться от других систем.

strftime([format [, timestamp]])

Эта функция возвращает цепочку . Она подобна функции с тем же именем в ANSI C. Время, указанное в timestamp, выдается в этой цепочке согласно формату в format. timestamp имеет тот же формат, что и значение, возвращаемое функцией systime. Если аргумент timestamp присутствует, gawk использует как отметку времени текущее время дня. Если отсутствует аргумент format, то используется "%a %b %d %H:%M:%S %Z %Y". Эта форматная строка выдает результат (почти) эквивалентный результату утилиты date. (Версии gawk до 3.0 требовали аргумент format.) Функция systime допускает сравнение отметки времени из регистрационного файла с текущим временем. В частности, легко определить, как давно некоторая запись была сделана. Она также позволяет вам сделать регистрационную запись, используя формат "seconds since the epoch". Функция strftime позволяет легко переделать отметку времени в удобную для человека форму. Это по своей природе сходно с функцией sprintf (См. раздел 12.3 [Встроенные функции для манипуляций с цепочками, стр. 137), в том, что она копирует буквально неформатные специальные символы в возвращаемую цепочку, подставляя дату и время для форматной обработки в форматную цепочку.

strftime гарантирует по стандарту ANSI C поддержку следующих спецификаций формата даты:

%a Местные сокращения названий дней недели.
%A Полные местные наименования дней недели.
%b Местные сокращения названий месяцев.
%B Полные местные названия месяцев.
%c Местное "принятое" представление даты и времени.
%d День месяца как десятичное число (01-31).
%H Час как десятичное число (24-час. часы) (00-23).
%I Час как десятичное число (12-час. часы) (01-12).
%j День года как десятичное число (001-366).
%m Месяц как десятичное число (01-12).
%M Минута как десятичное число (00-59).
%p Местный эквивалент для обозначения  AM/PM для 12-час. часов.
%S Секунды как десятичное число (00-60).5
%U Номер недели в году (первое Воскресенье как первый день недели один)
   как десятичное число (00-53).
%w День недели как десятичное число (0-6). Воскресенье как день 0.
%W Номер недели в году (первый Понедельник как первый день недели 1)
   как десятичное число (00-53).
%x Местное "принятое" представление даты.
%X Локальное "принятое" представление времени.
%y Год без столетий как десятичное число (00-99).
%Y Год со столетиями как десятичное число (e.g., 1995).
%Z Имя часового пояса или его сокращение или пусто, если зона не указана.
%% Литерал `%'.

Если спецификатор конверсии отличен от указанных, результат не определен.

6 Неформально, "локальный" означает географическое место, где программа должна исполняться. Например, обычный способ сокращения даты September 4, 1991 в Соединенных Штатах есть "9/4/91". Однако в многих странах Европы это будет "4.9.91". Так, спецификация `%x' в "US" регионе может выдавать `9/4/91', в то время как в регионе "EUROPE" она может выдавать `4.9.91'. Стандарт ANSI C определяет по умолчанию регион "C" как типичный для большинства программистов Си.

5 Изредка имеются минуты в году с несколькими секундами, не больше 60.

6 Это происходит потому, что ANSI C оставляет неопределенным поведение Си версии strftime, если она там есть. Обычно спецификатор конверсии или не появляется в возвращаемой цепочке, или появляется буквально.

Публичная Си-версия strftime поставляется c gawk для систем, которые еще не полностью согласованы с ANSI. Если эта версия использована для компиляции gawk (см. приложение B [Установка gawk], стр. 279), то доступны следующие дополнительные спецификации формата:

%D Эквивалент спецификации `%m/%d/%y'.
%e День месяца, пополненный пробелами в случае одной цифры.
%h Эквивалент для `%b'.
%n Символ новой строки  (ASCII LF).
%r Эквивалент для  `%I:%M:%S %p'.
%R Эквивалент для `%H:%M'.
%T Эквивалент для  `%H:%M:%S'.
%t Символ tab.
%k Часы (24-час. часы) как десятичное число (0-23). Одна цифра дополняется
   пробелом.
%l Часы (12-час. часы) как десятичное число (1-12). Одна цифра дополняется
   пробелом.
%C Столетия как число между  00 и 99.
%u День недели как десятичное число [1 (Понедельник)-7].
%V Номер недели в году (первый понедельник как первый день недели один) как
   десятичное число (01-53). Метод вычисления номера недели указан в ISO 8601
   (а именно: если неделя, содержащая 1 Января, имеет 4 или более дней в
   новом году, то она --- неделя 1, в противном случае это неделя  53 прошлого
   года, и только следующая неделя есть неделя 1).
%G Год со столетиями согласно счету недель по ISO как десятичное число.
   Например, 1 января 1993 лежит в неделе  53 года 1992. По ISO это еще год
  1992, хотя фактически уже 1993. Подобно этому, 31 Декабря 1973 лежит в
  в неделе 1 года 1974. Согласно нумерации недель по ISO, это уже
  год is 1974, хотя фактически еще 1973.
%g Год без столетий по нумерации недель в ISO как десятичное число (00-99).

%Ec %EC %Ex %Ey %EY %Od %Oe %OH %OI %Om %OM %OS %Ou %OU %OV %Ow %OW %Oy

Это "альтернативные представления" для спецификаций, которые используют только вторую букву (`%c', `%C', и т.д.). Они распознаются и используется их нормальные представления.7 (Это --- средство согласования с утилитами POSIX для обработки дат.)

%v Дата в формате VMS (e.g., 20-JUN-1991). %z Зонное смещение времени в формате +HHMM format (например, этот формат необходим для получения заголовков дат RFC-822/RFC-1036 date headers). Этот пример есть реализация в awk средств обработки дат в POSIX. Нормально утилиты дат печатают текущую дату и время в хорошо известном формате. Но если вы дадите в них аргумент, начинающийся с `+', дата скопирует неформатный символ спецификации и будет интерпретировать текущее время соответственно форматному спецификатору в цепочке.

Например:

$ date '+Today is %A, %B %d, %Y.'
a Today is Thursday, July 11, 1991.

Здесь использована версия gawk для утилит данных. Она имеет оболочечную "добавку" для обработки параметра `-u', который требует, чтобы дата воспринималась так, будто временная зона установлена на UTC.

#! /bin/sh # # date --- аппроксимирует P1003.2 'date' command
case $1 in -u) TZ=GMT0 # use UTC
export TZ shift ;; esac
gawk 'BEGIN -
format = "%a %b %d %H:%M:%S %Z %Y" exitval = 0
if (ARGC ? 2)
exitval = 1 else if (ARGC == 2) -
format = ARGV[1] if (format ~ /^"+/)
format = substr(format, 2) # remove leading + "" print strftime(format)&
 exit exitval ""' "$@"

7 Если вы не понимаете что-нибудь из этого, не беспокойтесь; эти средства предназначены для облегчения "интернационализации" программ.

В начало страницы

<<< Оглавление Страницы: 12  13 >>>