10. РАБОТА С ТЕКСТОВЫМИ ФАЙЛАМИ

При разработке и документировании программного обеспече-

ния неожиданно большое время занимает работа по созданию,

анализу, проверке и исправлению текстовых файлов. Она выпол-

няется достаточно простыми средствами печати файлов, поиска

строк, замены букв и строк, сравнения файлов и тому подоб-

ное. Соответствующие утилиты весьма эффективны для выполне-

ния таких работ по сравнению с обычным текстовым редактором.

 

 

 

- 83 -

10.1. Печать файла

Простейший способ печати - это перенаправление стандарт-

ного вывода команды cat на терминал, имеющий устройство пе-

чати.

Например:

$ cat file > /dev/lp.

Однако не все терминалы имеют собственное устройство пе-

чати. В случае общего устройства печати система обеспечивает

его коллективное использование, при котором заявка на пе-

чать, заставшая устройство занятым, ставится в очередь до

момента освобождения устройства, после чего ее требование

удовлетворяется автоматически. В этом случае используется

команда lpr или lp.

Например:

$ lpr file1 file2 file3

Имеются также команды просмотра очереди заявок на печать

lpstat и удаления заявки из очереди (cancel). Команды lpr и

lp не обеспечивают разбиение печати на страницы. Это может

быть сделано командой pr подготовки (prepare) файла для

постраничной печати, которая предшествует печати.

Пример:

$ pr myfyle | lpr.

Размеры страницы по умолчанию равны 66 строкам (длина -

length) по 72 знака (ширина - width). Ключами -w и -l можно

задать другие размеры.

Примеры:

$ pr -w 132 -h"Conversion program" conv.c | lpr

$ pr -l 25 addr | lpr

 

 

- 84 -

Ключ -h (head) вводит заголовок печати. Двойные кавычки

требуются при наличии в заголовке пробелов, иначе они могут

быть опущены.

 

10.2. Разборка и сборка файла

Многие команды ограничивают размеры файла, который они

могут обработать. Если ваш файл слишком велик, вы можете

разбить его на части командой split, а впоследствии после

обработки собрать из этих частей командой cat. Каждая часть

становится независимым файлом с именами по умолчанию xaa,

xab, xac, ..., xzz. Размер части по умолчанию - 1000 строк.

Пример:

$ split bigfile.

Можно изменить размер по умолчанию, задавая его явно,

например, 500 строк:

$ split -500 bigfile.

Можно задавать имена частей, например:

$ split bigfile ribs.

В этом случае имена будут ribsaa, ribsab, ... ribszz.

После необходимой обработки всех или некоторых частей

сборка файла из частей выполняется, например, следующим об-

разом:

$ cat ribs?? > bigfile.new,

где знаки вопроса - метасимволы, обозначающие любой символ.

 

 

- 85 -

Типичным примером применения технологии разборки - сборки

является печать отдельных избранных страниц файла.

Пример:

$ pr bigfile > bigpr

$ split -66 bigpr

$ lpr xaf xaj

Здесь будут напечатаны 6-я и 10-я страницы размером 66

строк исходного файла.

 

10.3. Сортировка текстовых файлов

Утилита sort упорядочивает записи файла в алфавитно-циф-

ровом порядке.

Пример:

$ sort people

Bill Williams 100

Henry Morgan 112

Mary Clark 101

$

Записи отсортированы по первой букве имени. Однако можно

выполнить сортировку и по фамилиям:

$ sort +1 people

Mary Clark 102

Henry Morgan 112

Bill Williams 100

$

 

 

- 86 -

Ключ +1 означает, что одно поле с начала записи было иг-

норировано при сортировке.

Сортировка по третьему полю с игнорированием лидирующих

пробелов выполняется с использованием ключа - b (blank):

$ sort -b +2 people

Bill Williams 100

Mary Clark 101

Henry Morgan 112

$

Для сохранения результата сортировки в файле используется

ключ -o (output):

sort -o sortpeople +1 people

Для слияния уже отсортированных файлов используется ключ

-m.

Пример:

$ sort +1 admpeople > sortadm

$ sort +1 hardpeople > sorthard

$ sort +1 sortpeople > sortsoft

$ sort -m +1 sortadm, sorthard, sortsoft > sortall

$

Имеется возможность удаления дублированных записей, ис-

пользуя ключ -u (uniq), а также сортировки по нескольким

несмежным полям.

 

10.4. Подсчет строк, слов, знаков в файле

Подсчет числа строк, слов и знаков в заданном файле вы-

полняется командой wc.

 

 

- 87 -

Например:

$ wc people

3 9 51 people

$

Ключи - l (lines), - w (words) - c (character) могут ука-

зать явно объекты счета.

Например:

$ wc -l people

3 people

$ wc -lc people

10 51 people

$

 

10.5. Поиск строк в файле по образцу (grep)

Утилита grep осуществляет поиск по одному или нескольким

файлам и печатает все строки, содержащие предъявленный обра-

зец текста, на стандартном выводе.

В простейшем случае образец задается постоянной строкой

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

(grep - акроним от global regular expression printer).

Пример:

$ grep Henry admpeople hardpeople softpeople

Softpeople: Henry Morgan 112

$

Или:

 

 

- 88 -

$ grep Henry *people

Softpeople: Henry Morgan 112

$

Ключ -v (invert) предписывает печать всех строк, кроме

найденных, например:

$ grep -v "Henry Morgan" Softpeople

Bill Williams 100

Mary Clark 101

$

Двойные кавычки требуются для размещения в образце пробе-

лов.

Регулярные выражения позволяют вести поиск типа: найти

все слова из четырех букв, начинающиеся на d, или все слова,

кончающиеся на able, и тому подобное. Рассмотрим примеры за-

дания образцов посредством регулярных выражений.

Знаки ^ и $ помечают начало и конец строки соответственно:

"^Genesis" - найти все строки, начинающиеся словом

Genesis;

"eschatus$" - найти все строки, кончающиеся словом

eschatus;

"^Out in cold$" - найти все строки, равные образцу.

Точка помечает любую букву:

"d..." - найти все слова из 4 букв, начинающиеся с d;

"d...$" - то же в конце строки;

"d..\ ." - найти все слова из 4 букв, начинающиеся с d и

оканчивающиеся точкой (знак \ - обратный слэш - отменяет

специальное значение следующего символа).

 

 

- 89 -

Квадратные скобы задают возможные значения знака:

"^ [abcxyz]" - найти все строки, начинающиеся с букв

a,b,c,x,y или z:

"[^Dd][a-z][a-z][a-z]" - найти все слова из 4 букв, не

начинающиеся с D или d, в которых последние три буквы - ма-

лые (от a до z).

Фигурные скобки задают количество повторений (замыкание)

предыдущего знака:

"[^Dd][a-z]{3}" - то же самое, что и предыдущий пример;

"[a-z]{3,5}" - найти все слова, содержащие от 3 до 5 ма-

лых букв.

Частные случаи замыкания обозначаются специальным обра-

зом:

* для {0} - ноль и более раз;

+ для {1} - один и более раз;

? для {0,1} - ноль или один раз.

Например:

$ grep ".*" people - просто напечатает все строки файла.

Примеры использования регулярных выражений:

уничтожить все пустые строки в файле:

$ grep -v "^ $" file > newfile;

уничтожить все строки, состоящие только из пробелов:

$ grep -v "^ *$" file > newfile.

 

10.6. Трансляция знаков (tr)

Утилита tr работает со стандартным вводом и имеет два ар-

гумента, задающие упорядоченные множества знаков, в которых

 

 

- 90 -

каждый знак первого множества заменяется соответствующим

знаком второго.

Пример:

$ tr a-z A-Z < people

MARY CLARK 101

HENRY MORGAN 112

BILL WILLIAMS 100

$

Ключ -d позволяет задать множество символов, которые бу-

дут уничтожены.

Например:

$ tr -d 0-9 < people

Mary Clark

Henry Morgan

Bill Williams

$

 

10.7. Команды сравнения файлов (diff, cmp, comm)

В процессе разработки программного обеспечения возникает

необходимость сравнения версий файла на разных этапах его

разработки. Узнать, чем версии отличаются друг от друга,

удобно командой diff, которая показывает разницу

(difference) двух файлов; сравнение файлов осуществляется по

строкам (записям). В результате выполнения команды печатают-

ся строки измененные (c), уничтоженные (d) и добавленные (a)

во втором файле-аргументе по сравнению с первым.

 

 

- 91 -

Пример:

$ cat people

Mary Clark 101

Sally Smith 113

Jane Buily 121

$ cat people.new

Mary Clark 101

Sally White 113

James Walker 112

$ diff people people.new

2 c 2

<Sally Smith 113

- - - -

>Sally White 113

3 d 2

<Jane Baily 121

3 a 3

>James Walker 112

Знаки < и > означают удаление и добавление строк; команда

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

Если строки отличаются только числом разделяющих слова

пробелов, также отличия можно подавить ключом -b (blank).

Например:

$ diff -b oldfile newfile

$.

 

 

- 92 -

Другая возможность быстрого сравнения файлов - команда

cmp (compare), реализованная на основе побайтового (побук-

венного) сравнения двух файлов.

Пример:

$ cmp people people.new

people, people.new differ: char 17, line 2

В качестве результата печатается число отличающихся бай-

тов (букв) и строк (линий).

Ключ -l (long) позволяет распечатать разницу файлов в ви-

де байтов (адрес и отличающиеся значения).

Например:

$ cmp people people, new

26 123 127

27 155 150

30 150 155

- - - - - - - -

197 60 61

198 60 61

Если файлы сильно отличаются друг от друга, сравнить их

эффективнее командой comm (common), которая показывает, что

в двух файлах одинаковое общее.

Например:

$ cat people

Mary Clark 101

Sally Smith 113

Jane Baily 121

 

 

- 93 -

$ cat people.new

Mary Clark 101

Sally White 113

James Walker 112

$ comm people people.new

Mary Clark

Sally Smith

Sally White

Jane Baily

James Walker

Результат команды comm печатается в три колонки: строки

первого файла, отсутствующие во втором: строки второго фай-

ла, отсутствующие в первом, и строки, общие для двух файлов.

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

его номер в виде ключа, например (печать только третьего

столбца):

$ comm -12 people people.new

Mary Clark

$

 

10.8. Обработка текстовых файлов командой awk

Awk - утилита, подобная grep. Однако, кроме поиска по об-

разцу, она позволяет проверять отношения между полями строк

(записей) и выполнять некоторые действия над строками (гене-

рировать отчеты). Название не является акронимом, оно обра-

 

 

- 94 -

зовано первыми буквами фамилий авторов (A.V.Aho,

P.Y.Weinberger, B.W.Kernighan).

Задание поиска-действия следует синтаксису:

/<образец>/{<действие>}

И образец, и действие могут отсутствовать. Найденные по

образцу строки при отсутствии заданного действия выводятся в

стандартный вывод (на экран).

Образец задается регулярным выражением, как и в grep. Ес-

ли образец отсутствует, обрабатываются все строки.

Рассмотрим примеры действий, которые можно выполнить ко-

мандой awk.

Перестановка полей строки выполняется с помощью ссылки на

поле $n, где n - номер поля.

Например:

$ cat people

Mary Clark 101

Henry Morgan 112

Bill Williams 100

$ awk '{print $2 "," $1 "^I" $3}' people

Clark, Mary 101

Morgan, Henry 112

Williams, Bill 100

где ^(control - I) - знак табуляции для подвода каретки к

очередной позиции табуляции (для выравнивания третьего по-

ля).

 

 

- 95 -

Действия для awk могут быть заданы в файле.

Например:

$ cat swap

{print $2 "," $1 "^I" $3}

$ awk -f swap people

Awk имеет встроенные образцы и переменные. Образцы BEGIN

и END означают начало и конец файла соответственно. Перемен-

ная NR (Number of Records) означает число записей (строк) в

файле, NF - число полей в записи. Можно использовать пере-

менные, объявленные пользователем. Пример, подсчитывающий

среднее значение третьего поля файла tennis (программа дейс-

твий для awk - в файле average):

$ cat > average

{total = total + $3}

END {print "Average value is", total/NR}

^D

$ awk -f average tennis

Average value is 8.9

$

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

Пример, в котором в файле tennis пишутся все записи, значе-

ние третьего поля в которых не меньше 10:

$ awk '$3 >= 10 {print $0}'tennis

Steve Daniel 11

Hank Parker 18

Jack Austen 14

$

 

 

- 96 -

Знак $0 (доллар-ноль) есть ссылка на всю запись (строку).

В общем случае выражение для условия подчиняется синтак-

сису, близкому к синтаксису выражений в языке C. Кроме того,

в команде awk допустимо указывать отрезок образцов. Пример

выборки всех записей, сделанных с 1976 до 1978 г.:

$ sort -n -o chard.s chard

$ awk '/1976/, /1978/ {if($2 < 8.00 print $0}' chard.s

1976 7.50 Chateau

1977 7.75 Chateau

1978 5.99 Charles

Как видно из примера, в программах действий для awk можно

использовать управляющие структуры с синтаксисом, близким к

языку C.

Пример цикла для печати полей всех записей файла в обрат-

ном порядке:

$ awk {for (i = NF; i > 0; --i) print $i} f1,

где NF - число полей в записи.

Полное описание средств awk можно найти в статье авторов

[6].