Чтение онлайн

на главную - закладки

Жанры

UNIX — универсальная среда программирования
Шрифт:

задает всю программу подсчета n печати сумм для пар имя значение независимо от порядка следования этих пар. Каждое имя (

$1
) служит индексом в массиве
sum
; в конце применена специальная форма цикла
for
для перебора всех элементов
sum
и их печати. Синтаксис этого варианта цикла
for
таков:

for (перем in массив)

 оператор

Хотя он может показаться вам искусственным, как цикл

for
языка
shell
, они никак не связаны. Цикл охватывает индексы массива, а не его элементы, устанавливая значение "перем" равным каждому
индексу поочередно. Однако порядок появления индексов непредсказуем, поэтому может возникнуть необходимость в их сортировке. В приведенном примере выходной поток можно по конвейеру передать команде
sort
, чтобы имена шли в порядке убывания значений:

$ awk '...' | sort +1nr

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

Использование ассоциативных массивов эффективно для вычислительных задач, таких, как подсчет частоты появления слов во входном потоке:

$ cat wordfreq

awk ' { for (i = 1; i <= NF; i++) num[$i]++ }

END {for (word in num) print word, num[word] }

' $*

$ wordfreq ch4.* | sort +1 -nr | sed 20q | 4

the 372 .CW 345 of 220 is 185

to 175 a 167 in 109 and 100

.PI 94 .P2 94 .PP 90 $ 87

awk 87 sed 83 that 76 for 75

The 63 are 61 line 55 print 52

$

В первом цикле

for
выбирается каждое слово из входной строки и заполняется массив
num
, индексируемый словами. (Не путайте
$i
, обозначающее в
awk
i-е поле входной строки, с переменными языка
shell
.) После того как файл будет прочитан, во втором цикле
for
печатаются в произвольном порядке слова и частота их появления.

Упражнение 4.9

В результат действия команды

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

sed 's/[->][->]*/\

/q' $* | sort | uniq -c | sort -nr

Строки

Хотя обе команды, и

sed
и
awk
, предназначены для решения небольших задач типа выбора определенного поля, только
awk
используется в той степени, в какой предполагает настоящее программирование. Примером может служить программа, которая разбивает длинные строки, чтобы они занимали не более 80 позиций. Каждая строка, превышающая 80 символов, завершается после 80-го символа; в качестве предупреждения добавляется
\
и обрабатывается остаток строки. Хвост разбиваемой строки сдвигается к ее правому концу, а не к левому, что более удобно для программ печати, и именно поэтому мы обратимся к программе
fold
. Рассмотрим, в частности, строки из 20, а не из 80 позиций:

$ cat тест

Короткая строка

Строка
немного длиннее

Эта строка еще длиннее, чем предыдущая строка

$ fold тест

Короткая строка

Строка немного длиннее

Эта строка еще длиннее,

 чем предыдущая строка

$

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

pr
в System V выполняет и то и другое. Наша реализация программы
fold
использует редактор
sed
, чтобы перевести символы табуляции в пробелы и чтобы счетчик числа символов в
awk
принял правильное значение. Это хороший способ при табуляции в начале строки (что типично для языковых программ), но номер позиции сбивается, если символ табуляции оказывается в середине строки:

# fold: fold long lines

sed 's/\(->/ /g' $* | # convert tabs to spaces

awk '

 BEGIN {

N = 80 # folds at column 80

for (i = 1; i <= N; i++) # make a string of blanks

blanks = blanks " "

 }

 {

if ((n = length($0)) <= N)

print

else {

for (i = 1; n > N; n -= N) {

printf "%s\\\n", substr($0,i,N)

i += N;

}

printf "%s%s\n" , substr(blanks, 1, N-n), substr($0, I)

}

 } '

На языке

awk
нет явной операции конкатенации строк; строки соединяются, если они следуют подряд. Вначале
blanks
является пустой строкой. Цикл в части
BEGIN
создает длинную строку пробелов конкатенацией: каждый шаг цикла прибавляет еще один пробел к концу строки
blanks
. Во втором цикле входная строка разбивается на части, пока оставшаяся часть не станет достаточно короткой. Как и в языке Си, операцию присваивания можно использовать в качестве выражения, поэтому в конструкции

if ((n=length($0)) <= N)...

длина входной строки присваивается

n
до проверки значения. Обратите внимание на скобки.

Упражнение 4.10

Измените программу

fold
так, чтобы разрыв строки происходил на пробеле или символе табуляции, а не посреди слова. Сделайте эту программу пригодной и для длинных слов.

Взаимодействие с интерпретатором

Допустим, что вы намереваетесь написать программу

field n
. Эта программа будет печатать n-е поле каждой входной строки так, чтобы можно было, например, задать:

$ who | field 1

для печати только имен, под которыми пользователи входят в систему. Язык

awk
явно предоставляет возможность выбора полей. Наша основная задача — передать номер n программе
awk
. Ниже приведено одно из возможных решений:

$ awk '{print $'$1'}'

Здесь

$1
открыто (не внутри каких либо кавычек), и поэтому становится номером поля, доступным в программе
awk
. При ином решении используются кавычки:

Поделиться:
Популярные книги

Сын Тишайшего

Яманов Александр
1. Царь Федя
Фантастика:
попаданцы
альтернативная история
фэнтези
5.20
рейтинг книги
Сын Тишайшего

"Искажающие реальность" Компиляция. Книги 1-14

Атаманов Михаил Александрович
Искажающие реальность
Фантастика:
боевая фантастика
космическая фантастика
киберпанк
рпг
5.00
рейтинг книги
Искажающие реальность Компиляция. Книги 1-14

Школа. Первый пояс

Игнатов Михаил Павлович
2. Путь
Фантастика:
фэнтези
7.67
рейтинг книги
Школа. Первый пояс

Невеста на откуп

Белецкая Наталья
2. Невеста на откуп
Фантастика:
фэнтези
5.83
рейтинг книги
Невеста на откуп

Убивать чтобы жить 2

Бор Жорж
2. УЧЖ
Фантастика:
героическая фантастика
боевая фантастика
рпг
5.00
рейтинг книги
Убивать чтобы жить 2

Вперед в прошлое!

Ратманов Денис
1. Вперед в прошлое
Фантастика:
попаданцы
5.00
рейтинг книги
Вперед в прошлое!

Аргумент барона Бронина 4

Ковальчук Олег Валентинович
4. Аргумент барона Бронина
Фантастика:
попаданцы
аниме
сказочная фантастика
фэнтези
5.00
рейтинг книги
Аргумент барона Бронина 4

Измена. (Не)любимая жена олигарха

Лаванда Марго
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. (Не)любимая жена олигарха

Измена. Право на обман

Арская Арина
2. Измены
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Право на обман

Бастард Императора. Том 7

Орлов Андрей Юрьевич
7. Бастард Императора
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 7

Жаба с кошельком

Донцова Дарья
19. Любительница частного сыска Даша Васильева
Детективы:
иронические детективы
8.26
рейтинг книги
Жаба с кошельком

Бастард Императора. Том 11

Орлов Андрей Юрьевич
11. Бастард Императора
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 11

Академия чаросвет. Тень

Ярошинская Ольга
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Академия чаросвет. Тень

Наследие Маозари 4

Панежин Евгений
4. Наследие Маозари
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Наследие Маозари 4