Брайан Керниган - UNIX — универсальная среда программирования
- Название:UNIX — универсальная среда программирования
- Автор:
- Жанр:
- Издательство:Финансы и статистика
- Год:1992
- Город:Москва
- ISBN:5-289-00253-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Брайан Керниган - UNIX — универсальная среда программирования краткое содержание
В книге американских авторов — разработчиков операционной системы UNIX — блестяще решена проблема автоматизации деятельности программиста, системной поддержки его творчества, выходящей за рамки языков программирования. Профессионалам открыт богатый "встроенный" арсенал системы UNIX. Многочисленными примерами иллюстрировано использование языка управления заданиями shell.
Для программистов-пользователей операционной системы UNIX.
UNIX — универсальная среда программирования - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
$ cat double
awk '
FILENAME != prevfile { # new file
NR = 1 # reset line number
prevfile = FILENAME
}
NF > 0 {
if ($1 == lastword)
printf "double %s, file %s, line %d\n" ,$1, FILENAME, NR
for (i = 2; i <= NF; i++)
if ($i == $(i-1))
printf "double %s, file %s, line %d\n", $i, FILENAME, NR
if (NF > 0)
lastword = $NF
}' $*
*
$
Операция ++означает автоувеличение операнда, а операция --— его автоуменьшение.
Встроенная переменная FILENAMEхранит имя текущего входного файла. Поскольку в переменной NRподсчитывается число строк с начала входного потока, мы изменяем ее значение всякий раз при изменении имени файла, чтобы точно указать строку с двойником.
Оператор if— такой же, как в языке Си:
if (условие)
оператор1
else
оператор2
Если условие верно, то выполняется оператор1; если оно ложно и если альтернативная часть присутствует, то выполняется оператор2. Альтернативная часть не обязательна.
Цикл forаналогичен таковому в языке Си, но отличается от цикла в языке shell:
for (выражение1; условие; выражение2)
оператор
Цикл forидентичен приведенному ниже оператору, который также допустим в программе awk:
Выражение1 while (условие) {
оператор
выражение2
}
Например, конструкция
for (i=2; i <= NF; i++)
является циклом с i, принимающим значения 2, 3 и т.д., включая число полей NF.
Оператор breakвызывает немедленный выход из цикла whileили for; оператор continueинициирует переход к следующему шагу цикла (к условию в операторе whileили к выражению2в операторе for). Оператор nextвызывает чтение следующей входной строки и сопоставление ее с шаблонами с начала программы awk, а оператор exit— немедленный переход на действия, определенные в шаблоне END.
Как и в большинстве языков программирования, в awkесть массивы. В качестве простого примера приведем программу awk, в которой каждая входная строка заносится в отдельный элемент массива, индексируемого номером строки, а затем они печатаются в обратном порядке:
$ cat backwards
# backwards: print input in backward line order
awk ' { line[NR] = $0 }
END { for (i = NR; i > 0; i--) print line[i] } ' $*
$
Заметьте, что подобно переменным, массивы не нужно описывать; размер массива ограничен только объемом памяти, доступным на вашей машине. Конечно, если очень большой файл заносится в массив, в конце концов, это может привести к исчерпанию ресурсов памяти. Для печати конца большого файла в обратном порядке следует обратиться за помощью к команде tail:
$ tail -5 /usr/dict/web2 | backwards
zymurgy
zymotically
zymotic
zymosthenic
zymosis
$
Команда tailиспользует возможности файловой системы — операцию "поиск" (seeking), позволяющую перейти к концу файла без чтения всей предшествующей информации. Подробнее эта операция будет рассмотрена при обсуждении функции lseekв гл. 7. (В нашей команде tailесть флаг -r, который определяет печать строк в обратном порядке, заменяя команду backwards).
При обычной обработке входная строка разбивается на поля. Эту операцию можно выполнить с помощью встроенной функции splitнад любой строкой:
n = split(s, arr, sep)
Строка sразбивается на поля, записываемые в элементы массива arrот 1 до n. Используется символ разделения полей sep, если он задан; в противном случае применяется текущее значение переменной FS. Например, обращение split($0, а, ":")разбивает входную строку на столбцы, что подходит для обработки файла /etc/passwd, поэтому обращение split("9/29/83", date, "/")разбивает дату по символам дробной черты.
$ sed 1q /etc/passwd | awk '{split($0, a, ":"); print a[1]}'
root
$ echo 9/29/83 | awk '{split($0, date, "/"); print date[3]}'
83
$
В табл. 4.5 перечислены встроенные функции awk.
cos(expr) |
Косинус expr |
exp(expr) |
Возведение в степень expr |
getline() |
Чтение следующей входной строки; возвращает 0 в случае конца файла, в противном случае 1 |
index(s1, s2) |
Положение строки s2в s1; возвращает 0, если строка не входит |
int(expr) |
Целая часть expr; округляет по минимуму |
length(s) |
Длина строки s |
log(expr) |
Натуральный логарифм expr |
sin(expr) |
Синус expr |
split(s, a, c) |
Разбиение sна а[1]... a[n]по символу c; возвращает n |
sprintf(fmt, ...) |
Форматирование в соответствии со спецификацией fmt |
substr(s,m,n) |
Подстрока в nсимволов строки s, начинающаяся с индекса m |
Таблица 4.5: Встроенные функции awk
Стандартной задачей обработки данных является получение суммарных значений для множества пар имя значение. Иными словами, по входному потоку типа
Susie 400
John 100
Mary 200
Mary 300
John 100
Susie 100
Mary 100
мы хотим получить суммарные значения для каждого имени:
John 200
Mary 600
Susie 500
Программа awkпредлагает изящное решение этой задачи — с помощью ассоциативных массивов. Хотя обычно мы представляем себе индекс массива как целое число, в awkлюбое значение можно использовать в качестве индекса. Поэтому
{sum[$1] += $2}
END {for (name in sum) print name sum [name]}
задает всю программу подсчета n печати сумм для пар имя значение независимо от порядка следования этих пар. Каждое имя ( $1) служит индексом в массиве sum; в конце применена специальная форма цикла forдля перебора всех элементов sumи их печати. Синтаксис этого варианта цикла forтаков:
for (перем in массив)
оператор
Хотя он может показаться вам искусственным, как цикл forязыка shell, они никак не связаны. Цикл охватывает индексы массива, а не его элементы, устанавливая значение "перем" равным каждому индексу поочередно. Однако порядок появления индексов непредсказуем, поэтому может возникнуть необходимость в их сортировке. В приведенном примере выходной поток можно по конвейеру передать команде sort, чтобы имена шли в порядке убывания значений:
$ awk '...' | sort +1nr
Реализация ассоциативной памяти предполагает хэширование, чтобы доступ к одному элементу занимал столько же времени, сколько и к любому другому, и чтобы это время не зависело (по крайней мере для массивов средних размеров) от числа элементов в массиве.
Читать дальшеИнтервал:
Закладка: