Текст
                    


МАТЕМАТИЧЕСКОЕ
ОБЕСПЕЧЕНИЕ
ЭВМ
С. Баурн
ОПЕРАЦИОННАЯ
СИСТЕМА UNIX
3
I
I




ФФФФФ4М
ФФФФФ4Н

Операционная система UNIX
INTERNATIONAL COMPUTER SCIENCE SERIES THE UNIX SYSTEM S.R. Bourne Bell Laboratories Addison-Wesley Publishing Company London-Reading, Massachusetts* Menlo Park, California Amsterdam • Don Mills* Ontario-Manila-Singapore Sydney.Tokyo 1983
МАТЕМАТИЧЕСКОЕ ОБЕСПЕЧЕНИЕ ЭВМ С.Баурн ОПЕРАЦИОННАЯ СИСТЕМА UNIX Перевод с английского Н. Б. Дерябина и О.А, Савицкой под редакцией Ю.М. Банковского Москва «Мир» 1986
ББК 32.973 Б 29 УДК 6Ф77.3 Баурн С. Б29 Операционная система UNIX: Пер с англ. — Мл Мир, 1986.—463 с. Описание одной из самых распространенных зарубежных операционных систем и языка С, данное известным американским специалистом. Книга отличается практической направленностью, материал хорошо систематизи- рован и доступен для первоначального ознакомления. Она интересна и с теоретической точки зрения как описание образца удачной операционной системы. Для программистов, работающих на СМ-4, для преподавателей вузов, аспирантов и студентов. 1702050000-341 Б 041 (01)-86 29-86, ч. 1 ББК 32.973 Редакция литературы по математическим наукам © 1983 Bell Telephone Labora tories, Incorporated © перевод на русский язык, «Мир», 1986
ПРЕДИСЛОВИЕ РЕДАКТОРА ПЕРЕВОДА Система UNIX была создана несколькими программистами в интересах небольшого коллектива. Первоначальная задача со- стояла в обеспечении удобной операционной среды на машине PDP 9, но затем задача несколько трансформировалась — нужно было перенести эту среду на машину PDP 11. Разработчики и не предполагали, что спустя короткое время система получит столь широкое распространение и, в сущности, станет стандартом де- факто. Чем объяснить этот феномен UN IX’а? Называют несколько причин. Во-первых, система UNIX в полной мере отвечает популярному принципу «красота в про- стоте»; она явилась антиподом операционной системе OS/360, которая для многих пользователей так и осталась «вещью в себе» из-за своей эклектичности и громоздкости. Во-вторых, универси- теты могли свободно, без всякой оплаты, получить систему, даже с исходными текстами, и она оказалась прекрасным педагоги- ческим материалом для целого поколения студентов, ставших затем ее проводниками в жизнь. В-третьих, благодаря языку С, на котором написана система UNIX, ее удается без чрезмерных затрат переносить на другие машины. Далее, появление системы UNIX совпало с началом эры микрокомпьютеров и персональных ЭВМ; в силу их разнообразия существенно усилился интерес к стандартизации операционных систем и как следствие к сис- теме UNIX. И наконец, немаловажную роль сыграл тот факт, что разработчики системы делали ее «для себя» и на себе испы- тывали — известно, что системам, сделанным из общих сообра- жений и рассчитанным на абстрактного пользователя, редко со- путствует успех. Разумеется, система UNIX не панацея от всех бед. Сама система требует развития и, очевидно, будет совершенствоваться. Можно выделить хотя бы следующие актуальные направления такого совершенствования: повышение надежности и эффектив- ности, обеспечение механизма виртуальной памяти и средств для работы в реальном масштабе времени, создание современного
Предисловие редактора перевода интерфейса с человеком (существующий одномерный текстовый язык команд уже не может удовлетворить), ориентация на мно- гопроцессорную, сетевую и распределенную обработку инфор- мации. Работы в этих направлениях уже ведутся. В книге С. Баурна отражено текущее состояние системы UNIX. Обширный материал по системе изложен очень компактно. Книга снабжена приложениями, которые превращают ее в спра- вочник, настольное руководство для программиста. Если принять во внимание еще и то, что автор книги непосредственно причастен к работам, связанным с системой, то можно утверждать: настоя- щая книга будет чрезвычайно полезна широкому кругу програм- мистов. Ю. Банковский
ПРЕДИСЛОВИЕ Предлагаемая книга является практическим руководством по системе UNIX; она будет полезна всем пользователям от нович- ков до профессионалов. Преимущества этой системы иллюстри- руются в тексте многочисленными примерами. Такие примеры, демонстрирующие связи между командами, помогут пользовате- лю полностью овладеть всей мощью системы UNIX. Во введении вкратце приведена история появления ранних версий системы UNIX и представлены компоненты системы, в том числе файлы и процессы. В последующих главах книги рассмат- риваются основные элементы системы UNIX, включающие управление файлами, управление процессами, системные вы- зовы, редактор, оболочку, язык С, форматоры текстов troff и nroff и средства обработки данных. Глава 2 знакомит пользователя с системой и с наиболее ши- роко используемыми командами. Разъясняется процедура входа в систему, описывается имеющаяся документация. Основные рассматриваемые здесь темы — оболочка и файловая система. Во всех последующих главах предполагается, что читатель озна- комился с этой главой. В гл. 3 представлены два редактора — ed и vi. Обе програм- мы предназначены для работы с терминала и используются для создания и модификации файлов. При чтении гл. 2 и 3 хорошо иметь под рукой терминал и испытать на практике некоторые команды. Если вы зайдете в тупик, попросите совета у вашего коллеги. Часто это самый быстрый способ научиться пользо- ваться системой. Оболочка обеспечивает интерфейс с системой UNIX как для пользователей, работающих в интерактивном режиме, так и при выполнении командных файлов, применяемых для на- стройки среды программирования в соответствии с потребностя- ми отдельных лиц или групп пользователей. В гл. 2 дается пер- воначальное представление об интерактивном использовании
8 Предисловие оболочки. Вопрос о том, как писать командные файлы (програм- мы), подробно рассматривается в гл. 4. В гл. 5 описание языка С приводится в объеме, вполне доста- точном для составления программ «разумного» размера. Знаком- ство с каким-либо другим языком программирования облегчит чтение этой главы. Здесь же рассматривается использование системы управления программами make и отладчика adb. В следующей главе описан интерфейс с системой UNIX для программистов, пишущих на языке С. Особое внимание уделяется написанию программ, которые используют возможности, предо- ставляемые непосредственно операционной системой. Эта глава предназначена для пользователей, пишущих системные команды на языке С. Приводятся также дополнительные сведения о фай- ловой системе, не упомянутые в гл. 2. Одним из главных применений системы UNIX является об- работка текстов и подготовка документов. В гл. 7 описывается набор программ nroff, troff, eqn и tbl, которые вместе с текстовым редактором облегчают создание и правку документов. В этой главе содержится также пример испытанного на практике пакета форматирования текстов, который использовался при подготовке английского оригинала этой книги. В последней главе рассматривается набор средств обработки данных, состоящий из таких программ, как awk, grep, sort и join, обеспечивающих гибкое управление небольшими базами данных или же обработку небольших объемов данных. Приво- дятся примеры полностью завершенных систем, в основу кото- рых положены эти средства. Каждый пример подробно разби- рается и рассматривается создание новых средств обработки данных, отсутствующих в стандартной системе UNIX. При чте- нии гл. 8 потребуются сведения из всех предшествующих глав. В приложениях дается сводка различных команд, используе- мых в книге. В этой книге многие аспекты системы UNIX рассматриваются с точки зрения пользователя. Предполагается, что читатель знаком с терминологией в области современной информатики. Благодарности В создании этой книги принимала участие большая группа лю- дей. Я в долгу у Эндрю Макгеттрика, без чьей помощи эта книга никогда не была бы закончена. Я весьма признателен Элу Ахо, Дугу Макилрою и Бобу Аллену, прочитавшим всю книгу от начала до конца и сделавшим подробные замечания.
Предисловие 9 Мне хотелось бы также поблагодарить Боба Морриса, Дэн- ниса Ритчи и других моих коллег из Computer Science Research Center за многочисленные обсуждения наиболее тонких моментов в системе UNIX. Я хотел бы поблагодарить Марка Баурна, Чарли Харриса, Питера Хонимэна, Джима Кайзера, Майка Леска, Дэйва Син- коски, Энди Таненбаума, Тода Тигера и ряд других сотрудников отделения, возглавляемого Энди Холлом (фирма Bell Laborato- ries), выборочно читавших ранние варианты книги и сделавших свои замечания. . Я признателен Саре Маллен и Энн Странк из издательства Addison Wesley и Джейн Баурн за помощь в контрольном чтении окончательного варианта книги. Большую помощь в подготовке первых версий книги оказали Мэрилу Бьюно, Джери Марки и Сью Уорд. Создание этой книги стало возможным благодаря прекрасным условиям в Computer Systems Research Laboratory, обеспеченным Бобом Лакки и Холлом Аллесом. Наконец, мне хотелось бы поблагодарить за поддержку чле- нов моей семьи.
Посвящается Джейн, Питеру, Марку и Саре ГЛАВА 1 ВВЕДЕНИЕ Слово UNIX обозначает семейство операционных систем, разра- ботанных фирмой Bell Laboratories. Система UNIX включает в себя как собственно операционную систему, так и набор свя- занных с ней системных программ-команд. Операционная сис- тема управляет информационно-вычислительными ресурсами (иерархической файловой системой, процессами) и выполняет прочие административные функции. К командам относятся ба- зисные средства обработки файлов и данных, редакторы, ассемб- леры, компиляторы, форматоры текстов. Существует мощный интерпретатор команд, позволяющий отдельным пользователям или пользовательским коллективам настраивать операционную среду на свой собственный лад путем определения своих соб- ственных команд. Большой интерес представляет история возникновения первой версии системы UNIX. В шестидесятые годы основные усилия в области разработки программного обеспечения были направле- ны на развитие языков программирования и операционных сис- тем. В это время были разработаны такие языки, как PL/I, APL, Симула 67, Алгол 68 и Кобол. Относительные достоинства и недостатки этих языков стали предметом дискуссий, часто до- вольно острых. В Великобритании Лондонский и Кембриджский университеты предприняли совместный проект по разработке комбинированного языка программирования — CPL (Combined Programming Language), но этот проект не был реализован в пол- ном объеме. Тем не менее в рамках этого проекта сформирова- лись основные понятия языка BCPL (Basic CPL), сыгравшего важную роль в истории создания системы UNIX. Операционные системы в те времена разрабатывались для ЭВМ среднего и высокого быстродействия как средства эффек- тивного разделения ресурсов между пользователями. В противо- положность пакетной обработке появились интерактивный режим работы и режим разделения времени. Были изучены стратегии управления страничной памятью, механизмы защиты, плани-
1.1. Историческая справка 11 рование заданий, принципы построения файловых систем и дру- гие родственные вопросы. Были разработаны операционные системы, такие, как CTSS (Крисмэн, 1965), Multics (Фейертаг, 1969) и (в Европе) Cambridge Multiple Access System (Хартли, 1968). Многие фундаментальные концепции системы UNIX заимствованы из этих систем. Так, например, файловые системы и независимый от устройств ввод-вывод, процессы и командные языки — все это в том или ином виде уже имелось в упомянутых системах. 1.1. ИСТОРИЧЕСКАЯ СПРАВКА Все началось с Кена Томпсона в 1968 году. Он тогда только что вернулся из Беркли, где Батлер Лэмпсон работал над созда- нием операционной системы SDS930 (Дейтч и Лэмпсон, 1965). Деннис Ритчи пришел в фирму Bell Laboratories в 1967 году из Гарварда, где занимался прикладной математикой. Томпсон оказался в группе талантливых людей, многие из которых только что прервали свои работы над системой Mul- tics — совместным проектом фирм Bell Laboratories, General Electric и Массачусетского технологического института. После отказа фирмы Bell Laboratories от участия в проекте Multics и ликвидации системы GE 645 в марте 1969 года перед исследо- вательской группой по информатике встала проблема замены вы- числительных средств. Предложения на установку нового обо- рудования рассматривались и затем отвергались из-за излишней дороговизны. К тому же после краха проекта Multics разработка операционных систем стала непопулярной областью исследова- ний. Самого Томпсона интересовали вопросы создания файловой системы, а совсем не операционной системы. Проект такой сис- темы сложился в ходе бесед между Раддом Кенеди, Томпсоном и Ритчи. Макеты первых версий файловой системы были написаны Томпсоном в системе GECOS. Другая ветвь истории связана с программой «космическое путешествие», написанной Томпсоном и Ритчи в системе GECOS. Эта программа плохо работала в системе разделения времени GECOS — требовалось более быстрое время ответа. В их рас- поряжении имелась ЭВМ PDP 7 с дисплеем 340, но в ее программ- ное обеспечение входили только ассемблер и загрузчик. В каж- дый момент времени на машине мог работать только один поль- зователь (в монопольном режиме). Такой режим работы был несовершенным, и вскоре стали появляться компоненты одно- пользовательской системы UNIX. Программа «космическое путешествие» была переписана для PDP 7. Были написаны и отранслированы в системе GECOS с использованием кроссассемб-
12 Гл. 1. Введение лера для PDP 7 ассемблер и ядро простейшей операционной системы. Эта первая система не обеспечивала разделение вре- мени: ЭВМ PDP 7, как и современные персональные компью- теры, имеет простейшее устройство и не годится для такого ре- жима работы. Вскоре в системе появились ассемблер и интер- претатор команд. Файловая система имела структуру ориенти- рованного графа с поименованными вершинами. Для всех под- оглавлений использовалось единое оглавление. С его помощью осуществлялись связи между файлами. Применение кроссассемблера означало использование двух ЭВМ и перенос перфолент с программами с одной ЭВМ на другую всякий раз при внесении изменений в программу. Система вскоре была модифицирована для PDP 7. При модификации системы возникла концепция образов процессов и был реализован при- митив образования нового процесса — fork. Затем появились основные обслуживающие программы (утилиты), такие, как копирование, редактирование, исключение и печать файлов. Система обеспечивала одновременную работу двух пользовате- лей. Брайан Керниган в 1970 году придумал для нее название UNIX. Группа все еще не имела своей собственной вычислительной машины. После ряда неудачных попыток для осуществления проекта подготовки текстовых документов Джо Оссанна пред- ложил приобрести PDP 11/20. В конце 1970 года PDP 11 была установлена, и начались работы по переносу системы на эту более мощную машину. Проект подготовки документов был успешно осуществлен, и патентный отдел фирмы, работавший на этом оборудовании совместно с исследовательской группой, стал первым пользова- телем системы UNIX. Томпсон и Ритчи составили руководство по этой первой версии системы, датированное ноябрем 1971 года. В этой версии были воплощены все важнейшие концепции, лежа- щие в основе современных версий системы UNIX, включая фай- ловую систему, управление процессами, системный интерфейс и основные команды-утилиты; единственным исключением были транспортеры. В июне 1972 года появилась вторая версия. По настоянию Дуга Макилроя в нее были включены транспортеры. Система и ее утилиты все еще были написаны на ассемблере. Томпсон за- нимался также и разработкой языка В (произносится «би») — на нем был написан ассемблер системы. Язык В — прямой по- томок BCPL, но компилятор В мог выдавать программу для ин- терпретации за один проход. Как В, так и BCPL — языки без типов данных, единственные объекты данных в них — машин- ные слова. Это затрудняло использование побайтных команд PDP 11, и поэтому в язык В были введены типы. Новый язык
1.1. Историческая справка 13 был назван NB, однако попытка переписать на нем систему оказалась неудачной. Для того чтобы ускорить выполнение программ, Ритчи начал работу над генератором кода для NB. Язык был назван С (произносится «си»), и, хотя тогда в нем еще не было структур и глобальных переменных, он оказался доста- точно заманчивым, так что новые утилиты стали писать непо- средственно на С. Очень плодотворным стал 1973 год. До сих пор система была написана на ассемблере, но после добавления структур в язык С она была успешно переписана на С. Томпсон написал управление процессами, а Ритчи — систему ввода-вывода. Шестая версия системы UNIX, ставшая первой широко распространенной версией, была закончена в мае 1975 года й распространялась за очень низкую плату. Работы по совершенствованию системы продолжались. Была написана новая файловая система, рассчитанная на файлы боль- ших размеров, и переделана оболочка системы с целью обеспе- чить более удобные средства программирования на командном языке. Последним значительным проектом Томпсона и Ритчи стало создание мобильной версии системы. Ее реализация велась на ЭВМ Interdata 8/32, машине с 32-разрядным словом, подобной ЭВМ серии IBM 370, но достаточно отличающейся от PDP 11 для того, чтобы вскрыть большинство машиннозависимых мест в системе. Этот проект привел и к ряду нововведений в язык С, среди которых — объединения, шаблоны и определения типов. Результатом этой работы стало создание Седьмой Версии систе- мы UNIX, доступной для широкого использования с 1979 года. И хотя шестая версия системы до сих пор используется, в боль- шинстве случаев она заменена седьмой версией. В настоящее время система UNIX считается стандартной операционной системой и реализована на самых разнообразных ЭВМ от микро до универсальных ЭВМ. Седьмая Версия была выпущена для ЭВМ PDP 11 с 16-разрядным словом. Первой системой для VAX 11/780 стала UNIX 32V, работа по переносу которой была выполнена также в фирме Bell Laboratories Джо- ном Рейзером и Томом Лондоном. Система получила дальнейшее развитие и в настоящее время распространяется Калифорний- ским университетом (Беркли, США). Развитие системы продол- жалось и в фирме Bell Laboratories. Сейчас версия UNIX Sys- tem V поставляется компанией Western Electric Company. Между этими версиями существуют некоторые различия как в операционной системе, так и в командах, но это не вызовет у читателя больших затруднений. Материал книги применим к каждой из этих систем, а особенности, присущие какой-либо одной из них, не рассматриваются. Программы, приведенные в этой книге, были скомпилированы и опробованы в системе
14 Гл. 1. Введение UNIX System V Bell Laboratories и в версии Калифорнийского университета (Беркли). Многие системные программы (команды) были первоначально написаны для ЭВМ PDP 11, адресное пространство которой ограничено 64К байтами. Это ограничение оказало в целом бла- гоприятное воздействие на программное обеспечение. Системы разрабатываются как набор легко стыкующихся компонент. Однако недостаток адресного пространства все же не позволил эффективно реализовать такие языки, как Лисп, до тех пор пока не появились машины с 32-разрядным словом. Система UNIX удачно спроектирована. Она стала эталоном простоты для операционных систем с разделением времени. Это одна из первых операционных систем, получивших широкое, применение на миниЭВМ, а именно на PDP 11. Сочетание этих факторов соответствовало потребностям факультетов универси- тетов, и целое поколение специалистов по информатике обуча- лось на системе UNIX. Первоначальный системный интерфейс выдержал испытание временем и не претерпел существенных изменений с момента первоначальной разработки. Эта стабильность послужила осно- вой для развития прикладных систем. Документация системы UNIX привлекает краткостью изложения, хотя некоторые и считают ее слишком краткой. Система UNIX оказалась на редкость удачной. Во время написания этой книги в мире насчитывалось свыше 3000 уста- новок, на которых она активно использовалась. Такие уста- новки можно найти в университетах, государственных учреж- дениях, коммерческих организациях и в разнообразных отрас- лях промышленности. В фирме Bell Laboratories система UNIX используется сотрудниками для разработки программ в диало- говом режиме, а также как система связи и система обработки текстов. Система UNIX мобильна, легко осваивается как поль- зователями, так и обслуживающим персоналом и предоставляет возможности, отсутствующие в других, иногда больших по раз- меру системах. 1.2. СРЕДА ПРОГРАММИРОВАНИЯ Система UNIX проста, изящна и предоставляет пользователям удобную среду программирования. Среди имеющихся средств — следующие: • компилятор языка С и отладчик; • ряд других языковых процессоров, включая APL, Бей- сик, Фортран 77, Паскаль и Снобол; • редакторы текстов ed, vi и emacs; • средства обработки текстов и подготовки документов
1.3. Концепции системы UNIX 15 (в том числе и содержащих математические формулы) tbl, eqn, troff и nroff; • средства построения компиляторов уасс и lex; • средства связи между пользователями mail и write; • средства машинной графики; • прикладные пакеты, например пакеты для расчета элект- рических цепей. Эти средства доступны пользователям через командный язык, обеспечивающий интерфейс между пользователями и опе- рационной системой UNIX. Программа, реализующая команд- ный язык, называется оболочкой, а программы, написанные на командном языке, иногда называются командными процедурами. Командный язык позволяет задавать в командах входные и выходные файлы и предоставляет типичные для алгоритмических языков управляющие конструкции. В существующей среде программирования сложилась мето- дика эффективной разработки программ, включающая в себя следующие рекомендации: • Стремитесь к тому, чтобы каждая программа выполняла только одну функцию. • Избегайте избыточного, хаотического, неструктурирован- ного вывода в программе. Имейте в виду, что вывод лю- бой программы может быть вводом для другой. • По мере возможности используйте или переделайте уже существующее средство, вместо того чтобы создавать новое, начиная с нуля. • Как можно скорее создайте маленький работающий про- тотип системы, а затем постепенно модифицируйте и на- ращивайте его до тех пор, пока не получится законченная система. При этом необходимо, чтобы каркас системы оп- ределился прежде, чем будет написана значительная, часть программы. 1.3. КОНЦЕПЦИИ СИСТЕМЫ UNIX 1.3.1. Файловая система Файловая система позволяет пользователям хранить поимено- ванные совокупности данных. Обеспечиваются средства защиты от сбоев аппаратуры и от несанкционированного доступа. Файло- вая система UNIX проста: отсутствуют блоки управления, спе- цифика устройств ввода-вывода скрыта от пользователя, для всех видов ввода-вывода используется единый интерфейс. В фай- ловой системе UNIX различаются три вида файлов. • Обычный файл содержит текст документа или программы. В виде обычных файлов хранятся также и выполняемые
16 Гл. 1. Введение программы (двоичные файлы). Концептуально файл со- стоит не из записей, а представляет собой просто после- довательность литер. Там, где это требуется, для выде- ления записей можно использовать литеру «новая стро- ка». ев оглавлении содержатся имена других файлов и/или оглавлений. Пользователь может создавать свои подо- главления для объединения файлов в группы по их тематике. Таким образом, файловая система является иерархической. Оглавление можно читать как обычный файл, но в него запрещено писать. • Устройствам ввода-вывода соответствуют специальные файлы. Внешне операции со специальными файлами ни- чем не отличаются от операций с обычными файлами, но обмен данными осуществляется непосредственно с уст- ройством, а не с файловой системой. Для специальных файлов предоставляются такие же средства защиты от несанкционированного доступа, как и для обычных файлов. 1.3.2. Процессы Исполнителями программ в системе UNIX являются процессы. Процесс — это единая последовательность событий. С процессом соотносятся некоторая часть памяти ЭВМ и множество доступ- ных файлов. Новый процесс создается путем копирования ста- рого. Единственное различие между старым и новым процесса- ми заключается в том, что старый (родительский) процесс может подождать завершения своего потомка. Процесс может заменить свою программу на новую и выполнить ее. Такой механизм и изящен, и эффективен. 1.3.3. Оболочка системы Оболочка — это в сущности командный' язык, который обеспе- чивает интерфейс пользователя с операционной системой UNIX. Оболочка выполняет команды, поступающие либо с терминала, либо из файла. Пользователь может строить свои собственные команды, создавая командные файлы (т. е. файлы, состоящие из команд). Эти новые команды имеют тот же статус, что и «систем- ные» команды. Таким образом, можно построить новую среду, отвечающую потребностям отдельного человека или группы пользователей. Транспортеры позволяют связывать процессы таким образом, что вывод от одного процесса становится вводом для другого. Командный язык предоставляет простые средства для использо- вания транспортеров.
ГЛАВА 2 НАЧАЛЬНЫЕ СВЕДЕНИЯ 2.1. ВХОД В СИСТЕМУ Прежде чем начать работу в системе, вы должны получить ре- гистрационное имя у администратора вашей системы. Если подключение к системе осуществляется через телефонную сеть, вам также нужно узнать телефонный номер вашей системы. Вместе с регистрационным именем вы получите пароль, который не позволит посторонним лицам войти в систему под вашим именем. Система UNIX обеспечивает работу с терминалами различных типов, начиная от простейших печатающих устройств и кончая графическими терминалами с высокой разрешающей способ- ностью. Поскольку терминалы отличаются друг от друга, убе- дитесь в том, что все параметры для вашего терминала установ- лены надлежащим образом. Такими параметрами являются: скорость ввода-вывода, контроль на четность (или нечетность), дуплексный режим (для удаленных терминалов) и наличие верх- него/нижнего регистров. Соединения по телефонным каналам связи (через модемы) обычно работают со скоростью 300 и 1200 бод, в то время как жестко замонтированные соединения, как правило, обеспечивают скорость 1200 или 9600 бод (300 бод — это примерно 30 литер в секунду). Когда вы первый раз подключаетесь к системе, она пытается определить скорость вашего канала связи по первой набранной вами литере. Обычно это литера возврата каретки (return). Если компьютер выдает на терминал бессмысленный набор литер, попробуйте просто нажать клавишу break (прерывание); в не- которых системах это сигнализирует о необходимости изменить скорость. В конце концов вы должны получить приглашение для входа в систему login: Теперь следует набрать свое регистрационное имя и нажать кла- вишу return, Пока вы не нажмете клавишу возврата каретки, система ничего делать не будет. Далее процедура login запросит ваш пароль. Пока вы набираете пароль, вводимые литеры не
18 Гл. 2. Начальные сведения будут отображаться на терминале (если это возможно для дан- ного терминала). Если введенные вами имя и пароль не зареги- стрированы в системе, будет выдано сообщение об ошибке login incorrect и вы снова получите приглашение для входа в систему. В не- которых реализациях процедуры login устанавливается тайм-аут на ввод пароля. Если вы за определенное время не наберете пароль, связь с системой будет прервана. Если вам удалось войти в систему, то, возможно, на терминал будет выдано сообщение, называемое «новости дня». За ним по- следует приглашение программы-оболочки — обычно это ли- тера $ или %. Теперь можно набирать команды. Если что-то не так и вы не можете войти в систему, следует обратиться за помощью к специалисту. Потенциальных причин для этого так много, что их невозможно здесь перечислить. 2.2. КОМАНДЫ Команда состоит из последовательности слов, разделенных пробелами или литерами табуляции. Первое (и, возможно, един- ственное) слово в команде — ее имя. Например, в ответ на коман- ду date на терминал будет выведена строка вида Wed Sep 1 12:12:19 EDT 1982 Три буквы EDT (Eastern Daylight Time) означают восточное по- ясное время. Команда who выдает список пользователей, работающих в системе в данный момент, упорядоченный по номерам терминалов, например: srb ityOO May 5 11:30 jmg ttyO1 May 5 21:22 lea tty13 May 5 22:29 cc tty29 May 5 16:11 jack tty41 May 5 08:39 В этом списке должна появиться строка, содержащая ваше соб- ственное регистрационное время, а также время входа в систему и номер вашего терминала (tty). Сокращение tty образовано от названия фирмы-изготовителя терминалов Teletype.
2.1. Характеристики терминала 19 Если команда состоит из нескольких слов, то второе и все последующие слова доступны выполняемой команде как пара- метры. Например, для того чтобы изменить свой пароль, войдите в систему и наберите passwd srb заменив srb на свое регистрационное имя. Команда passwd за- просит сначала ваш старый пароль, затем новый пароль и по- просит повторить новый пароль: Old password: New password: 'Retype new password: Рекомендуется использовать пароль длиной не менее шести ли- тер; в некоторых системах запрещается использовать пароль, состоящий менее, чем из шести литер. Практика показывает, что чем сложнее пароль, тем труднее его разгадать. При наборе па- ролей литеры не отображаются на терминале. Другим примером команды с параметрами является команда печати календаря cal. Она печатает календарь на определенный год или месяц. Если задан один параметр, то по команде cal печатается календарь на весь год, заданный этим параметром. Чтобы получить календарь на определенный месяц, требуется два параметра: месяц и год. Например, по команде cal 2000 на- печатается календарь на 2000 год, а по команде cal 9 1982 будет выдан календарь на сентябрь 1982 года: 1 September 1982 S М In W Th F S 12 3 4 5 в 7 8 9 10 11 12 13. 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 2.3. ХАРАКТЕРИСТИКИ ТЕРМИНАЛА Ошибки, допущенные при вводе с терминала, можно исправить путем стирания (erasing) отдельных литер или отмены (killing) всей строки и последующим вводом правильных литер. Для того чтобы стереть одну литеру, используется клавиша На- пример, строка passq^wd
20 Гл. 2, Начальные сведения эквивалентна строке passwd Для отмены строки используется клавиша Реакцией системы будет переход на новую строку. Эти две литеры (стирание и отмена) могут быть переопределены пользователем. В ранних версиях системы UNIX для стирания литеры и отмены строки применялись соответственно литеры 4k и Они и сейчас ис- пользуются по умолчанию; однако в дисплеях для стирания удобнее использовать литеру backspace (шаг назад). Для терминалов, работающих в коде ASCII, каждая вводимая строка заканчивается литерой return (возврат каретки). При вы- воде возврат каретки дополняется переводом строки (linefeed). Комбинация этих двух литер часто называется новой строкой (newline). Для установки параметров терминала служит команда stty. Естественно предположить, что от терминала к терминалу пара- метры варьируются. Пользователь может изменить параметры своего терминала. Например, команда stty erase ~ заменяет литеру стирания на так что теперь ввод слова whx~o эквивалентен вводу слова who. Если требуется ввести сами литеры 4k или @, то в качестве авторегистра используется литера\, отменяющая интерпрета- цию их как литер стирания и отмены. Таким образом, комбина- циях^ эквивалентна литере 4k, а \@—литере @. Если программа зациклилась или уже вывела достаточное количество информации, может оказаться необходимым прервать ее выполнение. Для этого следует нажать клавишу del или break, в результате чего вырабатывается сигнал прерывания. Оболочка и другие интерактивные программы обычно по прерыванию воз- вращаются на командный уровень и выдают приглашение для ввода очередной команды. Используя команду stty, можно заме- нить литеру del, возбуждающую прерывание, на другую ли- теру. Однако клавиша break порождает сигнал в канале связи и поэтому не может быть переопределена. В некоторых терминалах имеется механизм табуляции, для которого при включении терминала может понадобиться началь- ная установка. Для установки механизма табуляции терминала можно воспользоваться командой tabs. Не все старые терминалы выполняют табуляцию при выводе, а в некоторых нет клавиши для ввода табуляции (tab). На терминалах, не имеющих клавиши tab, литеру табуляции можно ввести как управляющее I (cont- rol-1). Если ваш терминал выполняет табуляцию неправильно, то можно воспользоваться командой stty —tabs. В результате
2.4. Документация 21 при выводе система будет заменять табуляции на соответствую- щее число пробелов. Предполагаемый интервал табулирования — 8 символов. В команде stty (см. приложение 1) имеется множество других вариантов для установки параметров терминала. Для обозначения управляющих литер, таких, как управляю- щее I, в книге используется сокращение вида Л1. Две другие управляющие литеры позволяют приостанавливать и возобнов- лять вывод на терминал. Литера AS приостановит вывод на тер- минал, а литера AQ возобновит его. Ввод любой другой литеры также возобновит вывод, а сама введенная литера будет передана в программу. Такое управление выводом невидимо для выпол- няющейся программы. 2.4. ДОКУМЕНТАЦИЯ Пользователь имеет доступ более чем к 150 различным системным командам. Сюда не относятся команды, написанные самими поль- зователями. Полные описания системных команд содержатся в UNIX Programmer's Manual (Руководство для программиста системы UNIX). Сведения о наиболее часто используемых командах системы UNIX приводятся также в приложении 1. Эту документацию можно также’ получить прямо из системы при помощи команды man, которая по заданному в ней имени команды выдает ее описание из руководства для пользователей. Например, команда man cal выведет страничку руководства с описанием команды cal (рис. 2.1)i). Ссылки на описания других команд делаются в виде имя-команды (том). Например, ссылка на описание команды stty имела бы вид stty (1). Все описания в руководстве имеют стандартный формат. Опи- сание состоит по крайней мере из трех разделов: ИМЯ (NAME) Приводится имя команды и ее значение. РЕЗЮМЕ (SYNOPSIS) Содержится краткое описание способа использования команды (ее формат). Слова, набранные жирным шриф- том, воспроизводятся при вводе команды без изменений. Остальные слова обозначают параметры команды, смысл которых поясняется в разделе ОПИСАНИЕ. Параметры, начинающиеся со знака минус, часто обозначают опции х) Описания, естественно, печатаются на английском языке, На рисунке дается перевод.'—Прим, перев.
22 Гл. 2. Начальные сведения данной команды. Квадратные скобки означают, что заключенные в них параметры можно опускать. Много- точие (...) указывает, что предшествующий ему параметр можно повторить произвольное число раз. Например, РЕЗЮМЕ для команды stty имеет вид stty [ опция . . . ]. За именем команды stty могут следовать одна или не- сколько опций. ОПИСАНИЕ (DESCRIPTION) Приводится описание действий, выполняемых командой, и смысл ее параметров. Могут присутствовать и другие разделы. В разделе ФАЙЛЫ (FILES) перечисляются используемые командой файлы; в разделе СМОТРИТЕ ТАКЖЕ (SEE ALSO) содержатся ссылки на род- CAL (1) UNIX. Руководство для программиста CAL(l) NAME cal — выдать календарь SYNOPSIS cal [месяц] год DESCRIPTION Команда cal выдает календарь на указанный год. Если задан и месяц, то календарь выдается только на этот месяц. Год задается числом от 1 до 9999. Месяц—это число от 1 до 12. Календарь выво- дится в виде, принятом в Англии и ее колониях. BUGS Считается, что год всегда начинается с января, хотя это чисто исторически сложившаяся услов- ность. Отметим, что “cal 78” относится к началу христианской эры, а не к 20 веку. Рис. 2.1 Вывод команды man cal ственные команды; в разделе ДИАГНОСТИКА (DIAGNOSTICS) обсуждается диагностика, которая может быть получена при выполнении команды; в разделе НЕДОСТАТКИ (BUGS) пере- числяются известные недочеты и ошибки, допущенные при разра- ботке и реализации команды. Руководство подразделяется на восемь томов. Информация распределяется по томам следующим образом: 1 Команды для пользователей. 2 Системные функции, интерфейс UNIX/C. 3 Библиотечные программы для языка С, в том числе стан- дартный пакет ввода-вывода (stdio) и библиотека матема- тических функций.
2.5. Файловая система 23 4 Специальные файлы. 5 Форматы файлов и соглашения о файлах. 6 Игры. 7 Пакеты обработки текстов. 8 Команды и процедуры для администратора системы. В приложении 1 данной книги содержится краткое описание команд системы, а в библиографии имеются ссылки на соответ- ствующие документы. Кроме man существует обучающая программа learn. Она может дать уроки по следующим темам: основные команды и работа с файлами; редактор; дополнительные возможности при работе с файлами; программа eqn для подготовки математических фор- мул; форматирующий пакет макроопределений —ms; введение в язык программирования С. 2.5. ФАЙЛОВАЯ СИСТЕМА Файловая система представляет собой иерархическую структуру с поименованными узлами. Каждое оглавление содержит имена файлов и оглавлений нижнего уровня. На структуру файла не накладывается никаких ограничений; каждый файл состоит про- сто из последовательности литер. Удобно, когда приняты согла- шения о структуре файлов, но в данном случае структура опре- деляется самостоятельно каждым программистом. Системе из- вестен формат файлов, содержащих выполняемые программы (файлы типа a.out). Полное (или составное) имя файла записывается в виде по- следовательности простых имен, разделенных косыми чертами. Составное имя /usr/srb/mbox начинается с оглавления //называемого корневым оглавлением, которое содержит оглавление usr. Оглавление /usr содержит оглавление srb, а внутри этого оглавления находится файл mbox. В приведенном примере имеются три оглавления:/,/usr и/usr/srb, каждое из которых, за исключением /, содержится в предше- ствующем (родительском) оглавлении. Длина каждого из про- стых имен, разделенных косыми чертами, не может превышать 14 литер. Простые имена не должны содержать косую черту и их не следует начинать с таких литер, как минус, так как это может привести к неправильной интерпретации опций и имен файлов в командах. Оглавления используются для объединения в группы файлов, имеющих общего владельца или связанных общей тематикой.
24 Гл. 2. Начальные сведения Первоначально администратор системы создает для каждого пользователя регистрационное оглавление. Пользователь rhm обычно получает оглавление /usr/rhm. Каждый работающий в системе пользователь имеет текущее (рабочее) оглавление. Команда pwd выдает полное имя текущего оглавления. Сразу после входа в систему текущим становится регистрационное оглавление поль- зователя. (См. также описание переменной $НОМЕ в оболочке.) Для задания нового текущего оглавления используется команда cd (изменить оглавление). Имена файлов можно зада- вать относительно текущего оглавления. Например, после вы- полнения команды cd /usr/srb/unix текущим оглавлением станет оглавление /usr/srb/unix, и на файл /usr/srb/unix/chl можно будет ссылаться, указывая только имя chi. Пользователь может создавать новые подоглавления для фай- лов, относящихся к разным темам, как это показано ниже. - usr - srb — - bin - include - src - cat - etc - lib - date passwd - group - cO - libc.a u’cds --- .. mbox Оглавление /usr содержит системные оглавления и оглавления пользователей. В оглавлении /etc содержатся системные файлы, в том числе и файл паролей. В оглавление /bin входят программы, реализующие системные команды, а в оглавлении /lib содержатся основные библиотеки программ, в том числе компилятор и биб- лиотека языка С. Более подробную информацию о структуре это- го оглавления можно найти в разделе hier Руководства для программиста системы UNIX.
2.5. Файловая система 25 2.5.1. Простейшие средства работы с файлами Команда cat (конкатенация) — одна из самых простых команд копирования файлов. Она копирует содержимое заданных файлов в стандартный файл вывода. По умолчанию, стандартный вывод происходит на терминал, хотя его можно направить и на дру- гое устройство (см. ниже). Команда cat обычно используется для вывода содержимого файла на терминал. Так, команда cat /etc/motd выводит файл /etc/motd. Этот файл содержит «новости дня», сооб- щаемые при входе в систему. Если в команде не задано ни одного параметра-имени файла, то cat читает данные из стандартного файла ввода. По умолчанию, стандартный ввод также осуществля- ется с терминала. Команду cat можно использовать для создания файлов путем ввода их содержимого с терминала, например: cat >newfile текст файла AD Вводимый текст помещается во вновь созданный файл newfile. Ввод заканчивается признаком конца файла, роль которого в случае терминала играет последовательность литер возврат каретки, AD (управляющее D). Такой способ создания файлов не всегда удобен. Для исправ- ления ошибок, сделанных при вводе, можно воспользоваться только литерами стирания и отмены. Гораздо удобнее для созда- ния файлов использовать редактор текстов; в этом случае ошибки можно исправлять по ходу редактирования. Редактирование файлов рассматривается в гл. 3. Для копирования содержимого одного файла в другой обычно используется команда ср (копирование). Она имеет вид ср from to Параметры from (откуда) и to (куда), задающие имена файлов, обязательны. Две команды cat file и ср file /dev/tty эквивалентны, поскольку /dev/tty — это имя файла, соответ- ствующего терминалу. Если необходимо, при выполнении команд ср и cat создаются новые файлы. Файлы можно также переименовывать и уничто-
26 Гл. 2. Начальные сведения жать. Команда гт исключает имя файла из оглавления и уничто- жает содержимое файла. Например, команда rm junk уничтожит файл junk в текущем оглавлении. Если файл был унич’ тожен по ошибке, то в некоторых случаях он может быть восста" новлен администратором системы. Команда mv перемещает (или переименовывает) файлы. На- пример, команда mv oldname newname переименует файл oldname (старое имя) в файл newname (новое имя). Имя файла изменяется, а содержимое остается неизмен- ным. Если файл с именем newname уже существует, то команда mv заменит его. Если при этом пользователь не имеет полномочий на запись в этот файл, система попросит его подтвердить свое намерение уничтожить файл, и, если в ответ будет введена буква у (т. е. «да»), файл уничтожается. Команды rm и mv следует ис- пользовать осторожно, поскольку они могут привести к потере информации. 2.5.2. Работа с оглавлениями Файлы можно создавать, уничтожать и переименовывать. Такие же операции могут применяться и к оглавлениям. Однако для оглавлений эти операции являются привилегированными и могут быть выполнены только при помощи команд: mkdir Создать оглавление. rmdir Уничтожить пустое оглавление. mv Переименовать оглавление. Если текущим оглавлением является /usr/mdm, то команда mkdir tmg создаст оглавление /usr/mdm/tmg, а команда rmdir tmg уничтожит его. Команда rmdir уничтожает только пустые оглав- ления, которые к тому же не являются текущими. При создании оглавления в нем для удобства автоматически создаются два стандартных элемента с именами . и .. . Имя . обо- значает само это оглавление, а имя .. — предшествующее (роди- тельское) оглавление. Поэтому имена файлов ./mbox и mbox эквивалентны. Если /usr/mdm/tmg — текущее оглавление, то после выполнения команды cd .. новым текущим оглавлением станет родительское оглавление /usr/mdm.
2.6. Оболочка 27 При помощи команд mv и ср можно переносить или копиро- вать группы файлов в заданное оглавление. Как команда mv файлг файл2 ... оглавление так и ср файлх файл2 ... оглавление выполняют эти действия, причем в новом оглавлении файлы со- храняют свои исходные имена. Первая команда переносит или переименовывает файлы, а вторая — копирует, сохраняя исход- ные экземпляры файлов неизменными. При переносе или копировании файлов в другое оглавление следует быть особенно внимательным и убедиться в том, что последним параметром действительно является оглавление, по- скольку команда mv также и уничтожает файлы. Например, команды mv х d mv yd mv z d переименуют файлы x, у и z в файлы d/x, d/y и d/z соответственно, если d — оглавление. В противном случае файл х переименовы- вается в d, затем файл у переименовывается в d, затирая при этом предыдущий файл. Наконец, файл z также будет переименован в d. 2.6. ОБОЛОЧКА Простейшие команды состоят из последовательности слов, раз- деленных пробелами. Первым словом является имя команды, которую нужно выполнить. Все остальные слова передаются вы- зываемой команде в качестве параметров. Например, команда 1s -1 выдает список имен файлов в текущем оглавлении. Параметр —I (от слова long — длинный) означает, что команда 1s должна на- печатать для каждого файла дату последнего обращения, размер и статус. Имена файлов в списке упорядочиваются по алфавиту. Для того чтобы выполнять команду, оболочка обычно создает новый процесс и ждет его завершения. Оба этих действия явля- ются примитивами операционной системы. Команду можно вы- полнять как фоновую и не ждать, пока она завершится. Для этого используется литера &, которая помещается непосредственно за командой. Например, print file &
28 Гл. 2. Начальные сведения запускает команду печати print с параметром file (имя файла) как фоновую. Литера & является металитерой, интерпретируе- мой оболочкой, и не передается команде print в качестве пара- метра. Для того чтобы дать возможность пользователю следить за ходом выполнения команды, оболочка после создания фонового процесса сообщает его номер. Список активных в данный момент процессов можно получить при помощи команды ps. Для каждого процесса в системе содержится набор дескрип- торов файлов с номерами 0, 1, ..., которые используются про- цессором и операционной системой во всех операциях ввода-вы- вода. Файл с дескриптором 0 называется стандартным файлом ввода (или просто стандартным вводом), а файл с дескриптором 1 — стандартным файлом вывода (стандартным выводом). При выполнении большинства команд результаты передаются в стан- дартный файл вывода, который первоначально (сразу после входа в систему) связан с терминалом. Имеется также стандартный файл диагностики, который обычно используется для вывода сообщений об ошибках. На время выполнения команды стандарт- ный файл вывода можно подменить (переназначить), например: Is —1 >файл Запись >файл интерпретируется оболочкой и не передается команде 1s как параметр. Если указанный файл не существует, оболочка создает его. В противном случае исходное содержимое этого файла заменится выводом команды 1s. Для дозаписи в конец файла используется обозначение >>, например: Is —1 >>файл Аналогично стандартным файлом ввода вместо терминала можно сделать обычный файл, например: wc <файл Команда wc печатает число литер, слов и строк в стандартном файле ввода. 2.6.1. Транспортеры и фильтры Стандартный вывод одной команды можно связать со стандарт- ным вводом другой команды при помощи транспортера — опе- ратора |. Например: 1s —1 I wc Две команды, соединенные таким образом, образуют конвейер, действие которого эквивалентно: Is —1 >файл wc <файл
2.6. Оболочка 29 за исключением того, что в этом случае не используется проме- жуточный файл. Вместо этого два процесса связываются транспортером, который создается путем обращения к системе. Транспортеры позволяют передавать данные только в одном на- правлении. Синхронизация осуществляется путем приостановки выполнения команды wc, когда нечего читать, и приостановки выполнения команды 1s при переполнении транспортера. Синхро- низацию осуществляет операционная система, а не оболочка. Фильтр — это команда, которая читает входные данные, преобразует их некоторым образом и выводит результат. Один из таких фильтров, grep, выбирает из своего файла ввода строки, содержащие некоторую заданную цепочку <питер. Например, Is | grep old распечатает из вывода команды 1s только те строки, которые со- держат цепочку литер old (если таковые имеются). Другой полез- ный фильтр — это команда сортировки sort. Например, who | sort распечатает упорядоченный по алфавиту список пользователей, работающих в данный момент в системе. Конвейер может состо- ять более чем из двух команд. Например, Is | grep old | wc —1 напечатает количество файлов в текущем оглавлении, имена ко- торых содержат цепочку литер old. 2.6.2. Порождение имен файлов Во многих командах параметрами являются имена файлов. На- пример, команда Is —1 main.с распечатает информацию о файле main. с. Оболочка предоставляет средства для порождения списка имен файлов по заданному образцу. Например, команда 1s —1 *.с порождает список параметров, содержащий все имена файлов из текущего оглавления, оканчивающиеся на .с. Литера * явля- ется образцом, который сопоставляется с любой цепочкой, вклю- чая и пустую. В общем случае образцы в командах задаются при помощи следующих металитер: * Сопоставляется с любой цепочкой литер, включая и пустую. ? Сопоставляется с любой одиночной литерой.
30 Гл. 2. Начальные сведения [. . .] Сопоставляется с любой из литер, заключенных в скобки. Пара литер, разделенных знаком минус, задает диапазон литер. Например, образцу [a—z]* соответствуют все имена из текущего оглавления, начинающиеся с одной из букв от а до z, а образцу /usr/fred/epns/?* соответствуют все имена из оглавления /usr/fred/epns, состоящие хотя бы из одной литеры. Если не окажется ни одного имени файла, соответствующего заданному образцу, в качестве пара- метра передается сам этот образец. Этот механизм позволяет, во-первых, сократить число литер, набираемых при, вводе команды, и, во-вторых, подбирать имена по некоторому образцу. Он может также использоваться для поиска файлов. Например, echo /usr/fred/*/core ищет и выдает имена всех файлов core в подоглавлениях оглав- ления /usr/fred. (Команда echo — это стандартная команда, ко- торая выводит список своих параметров, разделенных пробела- ми.) Выполнение данной команды может потребовать значитель- ных затрат, так как это связано с просмотром всех подоглавлений оглавления /usr/fred. Существует одно исключение из общих правил для образцов. Литера . в начале имени файла должна указываться явно. По- этому команда echo * выдает только те имена файлов из текущего оглавления, которые не начинаются с точки, а команда echo .* распечатает все те имена файлов из текущего оглавления, ко- торые начинаются с точки. Это позволяет избежать случайного сопоставления с именами . и .., обозначающими соответственно текущее и родительское оглавления. (Команда 1s не выводит ин- формацию о файлах . и .. .) Следует быть осторожным при использовании команды rm с образцами. Легко можно уничтожить больше файлов, чем было задумано. Один из способов уменьшить вероятность ошибки — применить сначала команду echo с данным образцом, например echo tmp*
2.6. Оболочка 31 а потом уже команду rm: rm tmp# Будьте внимательны — не введите случайно пробел между tmp и *. 2.6.3. Отмена специальных значений литер Литеры, имеющие специальное значение для оболочки, такие, как <, >, *, ?, | и &, называются металитерами. Любая ли- тера, если ей предшествует \, теряет свое специальное значение, если таковое имелось. Сама литера\отбрасывается, поэтому echo \? напечатает только ?, а echo \\ напечатает одну литеру \. Литера «новая строка», которой предшествует \, игнорируется (иногда это называют скрытой новой строкой). "Таким образом, длинные цепочки могут продол- жаться в нескольких строках. Литера \ удобна для отмены специального значения одиноч- ных литер. Если же требуется отменить специальные значения нескольких литер, такой способ оказывается неудобным и может привести к ошибкам. Специальные значения для групп литер можно отменить, заключив их в апострофы (одинарные кавычки). Например, результатом выполнения команды echo '*?[' будет цепочка литер *?[ Заключенная в апострофы цепочка литер не может содержать апострофы внутри себя, но может содержать литеры «новая стро- ка», которые сохраняются. Этот способ самый простой, его ре- комендуется использовать при каждом удобном случае. Существует также третий способ отмены специальных значе- ний литер, заключающийся в использовании (двойных) кавычек, при этом подавляется интерпретация некоторых, но не всех мета- литер. Подробнее этот вопрос будет рассмотрен в разд. 4.2.4. Комментарии в командном языке начинаются с литер 4k и заканчиваются литерой новой строки.
32 Гл. 2. Начальные сведения 2.6.4. Приглашения Когда оболочка обслуживает терминал, то перед считыванием очередной команды она выдает приглашение (подсказку). По умолчанию, таким приглашением является литера $. Пригла- шение можно заменить на любую другую цепочку литер, на- пример так: PSl=yesdear В результате в качестве приглашения будет использоваться цепочка литер yesdear. Если введена литера новой строки, а для завершения команды требуется продолжение ввода, оболочка выдаст приглашение >. Иногда это может произойти из-за не- соответствия кавычек. Если вы не желаете продолжить ввод, нажмите клавишу прерывания. Прерывание возвратит оболочку к чтению следующей команды. Это приглашение также можно изменить, введя, например, PS2=more 2.6.5. Оболочка и вход в систему Сразу после входа в систему вызывается программа-оболочка, которая читает и выполняет команды, вводимые пользователем с терминала. Если регистрационное оглавление пользователя содержит файл с именем .profile (так называемый входной файл), то оболочка выполнит его перед тем, как начать считывать коман- ды с терминала. date calendar MAIL=/usr/spool/mail/srb HOME==/usr/srb PATH«.:./bin:/bin:/usr/bin:$HOME/bin TERM==,.. export MAIL HOME PATH TERM Рис. 2.2 Типичный входной файл .profile Входной файл, приведенный на рис. 2.2, содержит типичные установки переменных оболочки, описываемых ниже в разд. 4.1.4. Этот входной файл также печатает дату и напоминания о бли- жайших мероприятиях. Команда export описывается в разд. 4.2.1.
2.7, Наиболее употребительные команды 33 Если вы всегда пользуетесь терминалами одного и того же типа, может оказаться полезной установка во входном файле перемен- ной TERM. 2.6.6. Сводка команд Is Напечатать имена файлов из текущего оглавле- ния. Is > file Is | wc - Поместить результаты вывода команды Is в файл file. -1 Напечатать число файлов в текущем оглавлении. Is 1 grep old Напечатать имена файлов, содержащие це- Is 1 grep почку old. old | wc —1 cc pgm.c Напечатать число файлов, имена которых со- держат цепочку old. & Выполнить команду сс как фоновую. 2.7. НАИБОЛЕЕ УПОТРЕБИТЕЛЬНЫЕ КОМАНДЫ 2.7.1. Средства связи В системе UNIX приятно работать, в частности, потому, что она предоставляет пользователям простые и удобные средства обще- ния друг с другом и с системой. Команды, описанные в этом раз- деле, позволяют пользователям, работающим на' одной и той же или на разных машинах, посылать почту другим пользователям или общаться друг с другом. Команда mail посылает сообщения (письма) другим пользователям, в то время как команда write используется для связи с пользователем, работающим за другим терминалом, в интерактивном режиме. Команда mail Команда mail позволяет принимать сообщения и посылать сооб- щения другим пользователям системы. Эти сообщения хранятся в некотором файле до тех пор, пока адресат не прочитает их и не уничтожит. Если вас дожидается почта, то при входе в систему вы полу- чите сообщение об этом. Оболочка также даст вам знать о поступ- лении любой новой почты перед выдачей на терминал очередного приглашения (см. описание переменной $MAIL в оболочке). Различным версиям системы UNIX соответствуют различные версии команды mail. В целом они функционируют одинаково, однако между ними существуют различия в деталях. Описывае- 2 С. Баурн
34 Гл. 2. Начальные сведения мый здесь вариант команды mail распространялся с седьмой вер- сией системы UNIX, Команда mail напечатает на терминале первое письмо из текущей почты, снаб- див его «почтовым штемпелем». Затем будет выдано приглашение ?. Полученное письмо можно уничтожить, набрав литеру d, на- печатать его снова, набрав р, или напечатать следующее письмо из текущей почты, нажав клавишу возврата каретки. Чтобы сохранить письмо в некотором файле, следует воспользоваться запросом s имя-файла Если в запросе s не указано имя файла, письмо будет сохранено в файле mbox в регистрационном оглавлении пользователя. Со- храненные и уничтоженные письма удаляются из почтового файла при выходе из команды mail. Выход осуществляется при помощи запроса q. Чтобы выйти из команды mail без каких-либо изменений в почтовом файле, следует воспользоваться запро- сом х. Это полезно в случае, если некоторые письма были уничто- жены по ошибке. В процессе обработки корреспонденции нажатие клавиши del приводит к прекращению выполнения текущего действия (обыч- но печати письма); выдается приглашение для ввода следующего запроса. Почту можно послать одному или нескольким пользователям с помощью команды mail jhc ken текст письма которая отправит письмо указанным пользователям (jhc, ken)t дополнив его именем отправителя и почтовым штемпелем. Текст письма заканчивается признаком конца файла или литерой введенной на отдельной строке. Если в процессе составления пись- ма произойдет какое-либо прерывание, то недописанное письмо будет сохранено в файле dead, letter в регистрационном оглавле- нии пользователя, и произойдет выход из команды mail. Почтовые системы обеспечивают связь между пользователями в пределах .одной машины. Связь между пользователями, рабо- тающими на разных машинах, осуществляется через специальную сеть, использующую обычные телефонные каналы. Такая сеть была создана и все еще применяется для пересылки файлов между машинами. Каждая машина, входящая в сеть, имеет некоторое имя и список имен и телефонных номеров других машин. Почто- вая служба использует эту сеть для доставки межмашинной
2.7. Наиболее употребительные команды 35 почты. Почтовый адрес состоит из имени машины и регистрацион- ного имени пользователя, разделенных восклицательным знаком. Например, для того чтобы послать почту пользователю 11с, находящемуся на машине с именем research, достаточно ввести команду mail research! 11с с последующим вводом текста письма. Некоторые машины могут также выполнять функции транзитного узла по пересылке почты. Так, команда mail allegra!ucbvax!wnj отправит письмо пользователю ucbvaxlwnj через транзитную ма- шину allegra. Такой транзит следует использовать только с со- гласия администрации промежуточной машины. Команда uucp Команда uucp (копирование UNIX — UNIX) копирует файлы с одной машины на другую. Связь между машинами устанавли- вается через телефонную линию, а в некоторых случаях использу- ются прямые высокоскоростные каналы связи. Команда uuname напечатает список имен систем, непосредственно доступных из вашей системы. Такая простая сеть ЭВМ эксплуатируется посто- янно. С машины (allegra), используемой автором, можно вы- звать свыше 300 машин. Формат команды uucp аналогичен формату команды ср. Например, команда uucp file research!/usr/srb/ufile скопирует файл file с местной машины на машину research; на новой машине файл будет иметь имя ‘/usr/srb/ufile. В своем первоначальном виде команда uucp могла использо- ваться для пересылки с машины на машину любых файлов. Един- ственными средствами защиты были средства, предусмотренные в файловых системах каждой из ЭВМ. Предоставление возможности произвольно копировать файлы в некоторую ЭВМ или из нее, зная ее телефонный номер и исполь- зуя относительно простой протокол, привело в ряде систем к не- допустимо высокой степени риска (с точки зрения обеспечения сохранности данных). Поэтому команда uucp накладывает на пересылаемые файлы дополнительные ограничения помимо огра- ничений, накладываемых файловой системой. Во многих систе- мах существует только одно оглавление, используемое для копирования файлов между машинами,—/usr/spool/uucppublic. Как правило это оглавление доступно всем пользователям 2*
36 Гл. 2. Начальные сведения данной машины, и каждый пользователь может создать в нем подоглавление для личного пользования. Администратор системы может разрешить использовать в команде uucp и любые другие оглавления. Команда write Помимо почтовой службы имеется команда write, позволяющая пользователям устанавливать связь между терминалами и не- посредственно общаться друг с другом. Команда write bill проверит, работает ли пользователь bill в системе в данный мо- мент, и, если да, пошлет на его терминал сообщение вида Message from srb on tty20 at 13:36 (сообщение от пользователя srb с терминала 20, время 13:36). Если пользователь bill вошел в систему более чем с одного тер- минала, то команда write сообщит об этом и выберет для связи один из этих терминалов. По принятому протоколу взаимодей- ствия bill должен ответить вводом команды write srb которая пошлет аналогичное сообщение на терминал инициатора диалога. Пользователь srb теперь может послать первое сообще- ние, например Hi, are you ready to eat lunch (о) Здесь (о) означает прием (over). Диалог продолжается до тех пор, пока одна из сторон не решит его закончить. Ввод признака конца файла AD завершит диалог на одном терминале и выведет текст EOF на другом терминале. Иногда, когда терминал используется как печатающее уст- ройство, или при работе с экранным редактором (см. описание редактора vi) появление случайного сообщения не желательно. Некоторые пользователи попросту предпочитают, чтобы их не прерывали. Команда mesg п запрещает другим пользователям посылать сообщения на ваш терминал, команда mesg у отменяет этот запрет, а команда mesg без параметров выдает информацию о текущем состоянии терминала (у или п).
2.7. Наиболее употребительные команды 37 2.7.2. Системные справки Команда ps Список всех активных процессов в системе можно получить с по- мощью команды ps (process status — состояние процессов). Опции и формат вывода этой команды различны в различных версиях PID ТТ STAT TIME COMMAND 22932 00 1 0:03 ed ama.temp 22864 16 S 0:07 vi t2 22963 16 S 0:00 sh -I 22968 16 R 0:00 ps a 22967 40 S 0:00 sleep 15 27786 40 S 6:28 /bin/sh /usr/haw/bin/print Рис. 2.3 Результат работы команды ps системы UNIX. Параметр а требует вывода списка всех процессов в системе; если он не задан, то выдается только список процессов, запущенных данным пользователем. Типичный вывод резуль- тата работы команды ps а приводится на рис. 2.3. Поля имеют следующий смысл: PID Идентификатор (номер) процесса. ТТ Номер терминала. STAT Состояние процесса: R — процесс выполняется, S — процесс приостановлен, I — процесс оста- новлен более чем на 20 секунд. TIME Время процессора, затраченное на выполнение команды (в минутах и секундах). COMMAND Выполняемая команда (вместе с параметрами). Команда du Эта команда определяет размер дискового пространства, отве- денного под файлы из некоторого оглавления и (рекурсивно) под файлы из всех его подоглавлений. Результатом работы команды du является список, содержащий имена файлов (оглавлений) и количество блоков по 512 литер, занятых этими файлами (оглав- лениями). Команда du без параметров выдает список, относящий- ся к текущему оглавлению. Если параметры заданы, то выдается список для указанных файлов и оглавлений.
38 Гл. 2. Начальные сведения Команда df Файлы хранятся в файловой системе, которой соответствует некоторая область на диске. Команда df печатает количество свободных и занятых блоков в каждой файловой системе. Еди- ницами дискового пространства являются блоки; блок обычно имеет размер 512 или 1024 байт (в зависимости от системы). В не- которых системах имеется постоянный дефицит дискового про- странства. Эта команда полезна, если вы собираетесь создавать большие файлы и хотите убедиться в том, что в файловой систе- ме достаточно свободного пространства. 2.7.3. Управление процессами Команды nice, nohup и kill Процесс, выполняющий любую команду, всегда конкурирует со всеми другими активными процессами в системе за процессорное время. Команда nice сообщает системе, что некоторое задание не является срочным и может выполняться с более низким приори- тетом. Например, nice ср largefile newfile выполнит команду ср largefile newfile с более низким приоритетом. Это ускорит выполнение других, более срочных заданий. Последовательность действий при работе за терминалом часто состоит из ввода команд и ожидания завершения их выполнения, как, например, при работе с файлами или при редактировании. Если выполнение команды или группы команд занимает много времени, то удобнее запустить это задание как фоновое и про- должить работу за терминалом. Для этой цели в командном языке предусмотрен оператор &. По команде ср largefile newfile & оболочка запустит копирование, однако не станет дожидаться его завершения. Команду nice также можно употреблять с опе- ратором &, так что по команде nice ср largefile newfile & копирование будет выполняться как фоновое и с низким приори- тетом. Если вы собираетесь выйти из системы и покинуть свой тер- минал, не дожидаясь завершения выполнения фонового задания, следует воспользоваться командой nohup. Это предотвратит
2.7, Наиболее употребительные команды 39 преждевременное завершение задания при отключении терминала и разрыве связи. Команда nohup используется аналогично коман- де nice, так что типичным примером является nohup ср largefile newfile & Если выполняющийся процесс больше не нужен, его можно уничтожить командой kill. В команде kill требуется указать номер (идентификатор) процесса, например номер, выданный командой ps. Обычно команда kill используется для уничтожения фоновых процессов. Однако процессы, запущенные посредством команды nohup, не восприимчивы к простой команде kill. Такие процессы можно уничтожать командой kill —9 идентификатор-процесса Такая форма команды kill обычно не используется, поскольку она не позволяет уничтожаемым процессам выполнить завершающие действия. Команда at Команда at дает возможность пользователям включать в очередь задания, которые будут выполняться в определенный момент в будущем. В каждой организации действуют свои правила, регламентирующие использование вычислительных ресурсов. На очень загруженных машинах, например, может быть неприемле- мым выполнение более одного фонового задания. Команду at можно использовать для того, чтобы отложить выполнение не очень важного задания до того момента, когда машина не будет столь загруженной. Все команды, описанные до сих пор, начинали выполняться сразу после их ввода. Запланировать выполнение задания в бу- дущем можно, воспользовавшись командой at. Например, при помощи at 1600 fri runcmd делается заказ на выполнение задания (командного файла) runcmd в ближайшую пятницу (friday) в 4 часа дня. Команда runcmd выполнится точно так же, как если бы она была введена только что, за исключением того, что ей не будет доступен тер- минал для ввода и вывода. Стандартные файлы ввода, вывода и диагностики следует обеспечить каким-либо другим образом. В системе нет специальных средств для отмены заданий, вве- денных посредством команды at. Эти задания хранятся в оглав- лении /usr/spool/at и могут быть уничтожены своим владельцем при помощи команды rm. В некоторых системах команда at отсутствует, хотя, может быть, в них имеются другие эквивалентные средства.
40 Гл. 2. Начальные сведения 2.7.4. Некоторые другие команды Команда calendar Команда calendar представляет собой службу напоминания (календарную службу) для индивидуального использования. Для того чтобы воспользоваться этой услугой, создайте в своем ре- гистрационном оглавлении файл calendar, содержащий строки вида июнь 27 9 часов посещение зубного врача Каждый день система будет просматривать этот файл и посылать вам по почте те строки, в которых содержится сегодняшняя или завтрашняя дата. Файл calendar остается неизменным и превра- щается в дневник событий. Команда file Команда file по содержимому файлов, имена которых заданы ей в качестве параметров, определяет тип этих файлов. Она недо- статочно надежна и иногда путает командные процедуры с про- граммами на языке С. Чтобы познакомиться с типичным выводом команды file, попробуйте ввести, например, file /usr/lib/* Команда find Команда find просматривает иерархию оглавлений, т. е. оглав- ление и, рекурсивно, его подоглавления, в поисках файлов, об- ладающих заданным свойством. Проверяются также условия, накладываемые на имя, возраст, владельца и полномочия файла. При обнаружении подходящего файла может быть выполнена некоторая команда или распечатано имя этого файла. Команда find поможет в случае, если вы не можете вспомнить имя оглав- ления, в котором находится файл, но помните имя самого файла. Команда find . —name precious —print просмотрит дерево оглавлений, корнем которого является теку- щее оглавление, и, если файл с именем precious будет найден, выведет его составное имя относительно текущего оглавления. Команда find . —name precious —exec Is —1 {} \; аналогична предыдущей, но при обнаружении файла precious выполнит также команду Is —1... . Каждый раз при выполнении команды 1s ее параметр, имеющий вид {}, будет заменяться на
2.7. Наиболее употребительные команды 41 полное составное имя найденного файла. Команда, которая будет выполняться, заканчивается комбинацией литер \;. Литера \ от» меняет специальное значение символа ; в командном языке. В следующих примерах приводятся другие варианты использо- вания команды find: find / —user mark—b —print Ищет во всей файловой системе (т. е. начиная с корня) файлы, принадлежащие пользователю mark—b. find . —size 0 —print Распечатает имена пустых файлов в текущем оглавле- нии и его подоглавлениях. Команда grep Команда grep уже встречалась в ранее рассмотренных примерах. Она просматривает файлы из заданного списка и выбирает из них строки, содержащие некоторую цепочку литер. Если не задано ни одного файла, просматривается стандартный ввод. Найденные строки копируются в стандартный вывод. Например, команда grep Unix * распечатает строки из файлов текущего оглавления, содержащие цепочку литер Unix. Если просматривается несколько файлов, grep добавляет в начало каждой выводимой строки имя файла. Общий формат вызова команды grep имеет вид grep образец [файл ...] Образец напоминает образец, используемый в командном языке для порождения имен файлов. В простейшем случае образец — это явная цепочка литер. Описание общего вида образцов при- водится в разд. 8.1. Вот несколько из наиболее употребительных в команде grep опций: — h Отмена печати имени файла в начале каждой строки. — п Перед каждой строкой выводится ее номер в файле. — v Печатаются только строки, не содержащие заданную цепочку литер. Команда 1s Команда Is выдает информацию о файлах и оглавлениях. Команда Is без параметров выведет имена файлов текущего оглавления в алфавитном порядке. Имена . и .. обычно не печатаются.
42 Гл. 2. Начальные сведения —d В случае оглавления выдавать только имя оглавления, а не имена содержащихся в нем файлов. —g Выдавать имя группы вместо имени владельца. —1 Выдавать (длинный вариант): полномочия файла, число ссылок на файл, имя владельца, размер файла и время последней модификации. —г Изменить порядок выводимых строк на обратный. ‘ —t Упорядочивать по времени последней модификации, а не по имени файла. —и Использовать (для вывода или сортировки) время по- следнего доступа вместо времени последней модифика- ции. Команда od Файлы, содержащие непонятные литеры, можно распечатать с помощью команды «восьмеричного дампа» od. Например, команда od —b file выводит каждый байт файла file в виде целого восьмеричного числа. Вот некоторые другие опции команды od: —с Печать в коде ASCII. Для представления неграфических литер в качестве авторегистра используется литера \. —х Печатать по 16 бит в шестнадцатеричном виде. Файлы с более сложной структурой можно распечатать с по- мощью отладчика adb. Команда рг Листинги одного или нескольких файлов можно получить, вос- пользовавшись командой рг. Например, команда рг *.с распечатает все файлы из текущего оглавления, имена которых оканчиваются на .с. Выводимый текст разбивается на страницы по 66 строк. В начале каждой страницы помещается заголовок, содержащий имя файла, дату, время и номер страницы. Последняя страница дополняется пустыми строками до целой страницы. Вот наиболее часто используемые опции: —t Отменить вывод дополнительных (пустых и содержа- щих заголовок) строк в начале и в конце каждой страницы. —п Выполнять вывод в п колонок.
2.7. Наиболее употребительные команды 43 —h текст Использовать текст в качестве заголовка каждой страницы. —ш Слияние. Одновременная печать нескольких файлов. Каждый файл печатается в отдельной колонке. Команда stty Терминалы могут иметь совершенно различные характеристики. Параметры терминалов сообщаются системе посредством коман- ды stty. Команда stty без параметров выдает текущие установки наиболее важных параметров терминала, таких, как скорость обмена, контроль на четность или нечетность, литеры стирания и отмены. Если ваш терминал ведет себя странным образом, следует проверить соответствие его конфигурации и действующих опций команды stty. Организация ввода-вывода для терминалов обсуждается в гл. 6. Команда tar Файлы можно копировать на магнитную ленту и с магнитной ленты, используя команды cat или ср. Однако копирование от- дельных файлов таким образом не очень удобно. Команда tar (архив на ленте) копирует целое оглавление или дерево оглавле- ний обычно с ленты на диск или с диска на диск. Например, команда tar гс . считает все файлы и (рекурсивно) все подоглавления из текущего оглавления (.) и запишет их на ленту. Опция г задает чтение оглавления, а опция с создает новый архив на ленте. Лента — это специальный файл наподобие /dev/tty, имя которого зависит от системы. Имя этого специального файла можно не указывать, поскольку оно встроено в команду tar. Чтобы получить список имен файлов, хранящихся на ленте, используется команда tar t Опция t означает titles — заголовки. Файлы могут считываться с ленты и записываться на диск командой tar х Имена записанных на диск файлов совпадают с именами, выдан- ными командой tar t. Имена, задаваемые в команде tar, следует указывать относи- тельно текущего оглавления, для того'чтобы можно было счи-
44 Гл. 2. Начальные сведения тывать файлы в другое место файловой системы. Например, вместо tar rc /usr/srb лучше воспользоваться командами cd /usr/srb tar rc. 2.7.5. Сводка команд Следующие команды позволяют пользователю войти в систему и начать работу за терминалом. login mail man stty who Запрашивает регистрационное имя и пароль. Посылает и получает почту. Печатает разделы из руководства для пользователя. Устанавливает параметры терминала. Выдает список пользователей, работающих в сис- теме в данный момент. Были также рассмотрены следующие важные команды для рабо- ты с файлами. cat ср Is mkdir mv Конкатенация и печать файлов. Копирование файлов. Получение списка элементов оглавления. Создание оглавления. Перемещение или переименование файла или оглав- ления. rmdir rm pr Уничтожение оглавления. Уничтожение файла. Форматирование и печать файла.
ГЛАВА 3 РЕДАКТИРОВАНИЕ ФАЙЛОВ Редактор текстов дает возможность пользователю непосредствен- но с терминала создавать файлы, содержащие программы, тексты документов и т. п., а также вносить в них изменения. Редакторы являются интерактивными, что позволяет пользователю вести диалог с системой. Существует два общедоступных редактора: ed и vi. Из них ed более широко распространен и использует только базисные средства, имеющиеся на любом терминале. Другой редактор, vi, является экранным редактором и рассчитан на работу с дисплея- ми. В этой главе описываются характерные особенности обоих редакторов. 3.1. РЕДАКТОР ed Редактор ed вызывается командой ed На терминал не выдается никакого приглашения; редактор будет ждать ввода запроса на редактирование. Термин запрос исполь- зуется для того, чтобы отличить инструкции, задаваемые коман- дам (т. е. программам, вызываемым на уровне оболочки) от самих команд. Редактор ed хранит редактируемый текст в области памяти, называемой буфером, и выполняет запросы, позволяющие до- бавлять, исключать и изменять текст. Имена всех запросов со- стоят из одной буквы. За исключением особо указанных случаев, в одной вводимой строке не может быть более одного запроса. При любой ошибке ed напечатает символ ? и будет ждать ввода нового запроса.
46 Гл. 3. Редактирование файлов 3.1.1. Создание файлов Изначально буфер редактора пуст. Чтобы поместить в буфер информацию, используется запрос дозаписи текста a (append — добавление): а текст, который нужно поместить в буфер Пока вводится текст, редактор находится в режиме дозаписи. Для того чтобы закончить ввод текста и выйти из режима доза- писи, требуется в отдельной строке ввести точку (точка должна стоять в начале строки и за ней должен следовать возврат ка- ретки). Содержимое буфера записывается в файл draft. 1 при по- мощи запроса записи w draft. 1 Литера w (write — запись) отделяется от имени файла пробелом. В ответ редактор выдает количество литер, записанных в файл. После выполнения этого запроса содержимое буфера не меняется. Записав содержимое буфера в файл, можно выйти из редактора при помощи запроса выхода q (quit). К выходу из редактора приведет также ввод признака конца файла — литеры AD. Если содержимое буфера менялось и не было записано обратно в файл, редактор на запрос w или q ответит литерой ?. Обычно это един- ственное сообщение об ошибке, получаемое от редактора, и оно может сбить с толку начинающего пользователя. Приведем ти- пичные ошибки, возникающие при работе с ed: • Несуществующий запрос. • Ошибка в формате запроса. • Файл не существует, или его нельзя читать, или в него нельзя писать. Выше был описан способ создания файла, но ничего не было сказано о том, как редактировать содержимое уже существую- щего файла. Точно так же как запрос w draft, ch 1 записывает содержимое буфера в файл, запрос е draft, ch 1 считывает содержимое файла draft.ch 1 в буфер, уничтожая все, что было в буфере до этого. Вот один из способов вызова редактора ed:
3.1. Редактор ed 47 ed e имя-файла [Запросы редактирования, изменяющие содержимое буфера] w имя-файла Ч Тот же результат можно получить и другим способом: ed имя-файла [Запросы редактирования, изменяющие содержимое буфера] w q Если имя файла передается редактору ed как параметр вызова, то запрос е не нужен. Кроме того, нет необходимости помнить имя редактируемого файла для того, чтобы в дальнейшем ука- зать его в запросе w (как во втором примере). Редактор хранит имя редактируемого файла. Это имя переустанавливается при выполнении запросов е и w. Его можно вывести при помощи запроса f. 3.1.2. Редактирование строк текста Текст в буфере состоит из строк, и ряд запросов выполняет опе- рации над строками текста. Общий формат запросов имеет вид: начальная-строка, конечная-строка запрос Запрос применяется к каждой строке буфера от начальной-стро- ки до конечной-строки включительно. Строки можно адресовать по номерам, начиная с 1. Если начальная и конечная строки сов- падают, можно использовать сокращенную форму: конкретная-строка запрос В следующих примерах приведен ряд наиболее употребитель- ных запросов редактирования. 1,4р Распечатать строки с номерами от 1 до 4 включи- тельно. 1,4п Распечатать строки с 1 по 4 включительно, вна- чале каждой строки помещается ее номер. 10,15d Исключить строки с 10 по 15 включительно. 4,14w parti Записать строки с 4 по 14 включительно в файл с именем parti. Если начальная и конечная стро- ки не заданы, записывается весь буфер. 4г new. part Считать содержимое файла new. part и вставить в буфер непосредственно после строки 4; если но- мер строки не задан, содержимое файла записы- вается в конец буфера. 4,14т21 Перестановка строк. Строки с 4 по 14 изымаются
48 Гл. 3. Редактирование файлов со своего места и помещаются за строкой 21 (и перед строкой 22). И2 Поместить копию строки 1 за строкой 2. Команды г, m и t помещают текст после заданной строки. Последняя строка буфера адресуется при помощи литеры $. Так, запрос l,$d исключает из буфера все строки с первой по последнюю включительно. Этот запрос следует использовать только тогда, когда нужно очистить весь буфер. Аналогично запрос 1,$р распечатывает содержимое всего буфера. Текущая строка В каждый момент времени одна из строк буфера является те- кущей. На нее как бы показывает некоторый указатель. Ссыл- кой на текущую строку является точка. Текущей обычно яв- ляется последняя отредактированная строка. После выполнения запроса а это последняя введенная строка, а после выполнения запроса m — последняя из переставленных строк. Запрос d является исключением, так как последней редактировавшейся строки больше не существует; текущей становится строка, сле- дующая за исключенными. В сомнительных ситуациях текущую строку можно распечатать при помощи запроса р. Кроме того, номер текущей строки можно узнать, введя запрос .= . Чтобы сделать текущей некоторую строку без выполнения каких-либо редактирующих действий, наберите ее номер. Так, запрос 4 вы- водит строку 4 и присваивает указателю текущей строки (точке) значение 4. Вообще всегда, когда устанавливается новая текущая строка и требуется ввести новый запрос редактирования, эта текущая строка выводится. Адресация строк Строки в редакторе ed можно адресовать по их порядковым но- мерам. Для указания текущей строки можно использовать точку, а для указания последней строки текста — литеру $. Адреса можно образовывать также путем прибавления к одной из этих величин или вычитания из нее некоторого числа (прибавление к $ всегда вызовет ошибку). Адреса, начинающиеся с «+» или «—», берутся относительно текущей строки. Знаки + и — сами по себе используются для продвижения вперед или назад на одну строку. В приведенных ниже запросах редактирования иллюстри- руются типичные способы адресации строк. + Перейти к следующей строке и распечатать ее. — Вернуться назад на одну строку и распечатать ее.
3.1. Редактор ed 49 .,$d Исключить все строки до конца буфера, начиная с текущей. •-1..+ 1Р Распечатать предыдущую, текущую и следующую строки. .4-2,$—1р Распечатать все строки, начиная со строки с но- мером, превышающим номер текущей строки на 2, вплоть до предпоследней (включительно) стро- ки буфера. Во всех случаях значение указателя текущей строки (точки) изменяется. Добавление и исключение текста Общим средством добавления нового текста в буфер является запрос дозаписи. Запрос 10а текст, который нужно поместить между строками 10 и И поместит введенный текст в буфер непосредственно за строкой 10. Имеются два других похожих на а запроса. Можно заменять строки, используя запрос с, сочетающий в себе исключение и вставку текста. Например, запрос 4,27с новый текст заменяет данным текстом строки с 4-й по 27-ю включительно. Как и следовало ожидать, запрос 4с добавляемый текст заменит строку 4. В обоих случаях ввод текста завершается строкой, содержащей только точку. Запрос вставки i внешне похож на запрос а, но вставляет текст перед указанной строкой, а не за ней. Так, запрос 11 .се 2 Глава 1 .sp 2 Основные принципы .sp 2
50 Гл. 3. Редактирование, файлов добавляет новый текст в начало буфера. Эквивалентный резуль- тат достигается при помощи запроса 0а Если в запросах а, с, d, i и р номера строк не заданы, то, по умолчанию, используется номер текущей строки, так что запрос а добавляемый текст эквивалентен запросу .а добавляемый текст Кроме того, запрос d исключает текущую строку, а последующий запрос р печатает новую текущую строку, т. е. следующую стро- ку буфера. Эти запросы можно записать в одной строке в виде dp После выполнения каждого из запросов а, с, i и m текущей строкой становится последняя добавленная, замененная, встав- ленная или передвинутая строка соответственно. 3.1.3. Поиск по контексту Ссылаться на строки только по номерам неудобно, если под рукой нет листинга. К тому же простые вставки и удаления приводят к изменению нумерации строк. Удобнее при помощи редактора найти некоторую цепочку литер, проверить, что найдена именно нужная строка, а затем отредактировать ее и просмотреть снова. Например, запрос /Fotran/ будет искать в буфере следующую строку, содержащую цепочку литер, ограниченную косыми чертами. Найденная строка выво- дится, так что можно проверить, является ли она искомой. При поиске редактор последовательно просматривает строки текста, начиная со строки, следующей за текущей. Дойдя до конца бу- фера и не встретив подходящую строку, редактор продолжит поиск с начала буфера и будет искать до тех пор, пока не про- смотрит все содержимое буфера, дойдя опять до текущей строки. Если подходящей строки нет (возможно, из-за ошибки в запро- се), выводится литера ?.
3fl. Редактор ed 51 Задание образца для поиска (например, /Fotran/) является одним из способов адресации строки. Образцы поиска рассмат- риваемого здесь вида можно использовать точно так же, как выше использовались номера строк. Например, запрос /switch/,/case/d удаляет весь текст между ближайшей строкой, содержащей це- почку литер switch, и ближайшей строкой, содержащей цепочку case. Предполагается, что строка, содержащая case, следует за строкой, содержащей switch, или совпадает с ней. Дойдя до последней строки буфера и не встретив подходящую строку, ed продолжит поиск с первой строки. Поиск заканчива- ется при достижении текущей строки или когда встретится под- ходящая строка. Образец поиска можно использовать как часть адреса. На- пример, запрос /main/— 1 сделает текущей строку, предшествующую ближайшей строке, содержащей цепочку литер main. Использование точки с запятой Запрос /begin/, /end/d начинает поиск цепочки end с того же самого места, с которого начинался поиск цепочки begin, т. е. с текущей строки. Для того чтобы поиск цепочки end начался с того места, где встретилась цепочка begin, в качестве разделителя используется вместо за- пятой точка с запятой, как, например, в запросе /begin/;;/end/d Поиск в обратном направлении При поиске по контексту с использованием конструкции /.../ текст просматривается в прямом направлении (от начала к концу буфера). Конструкция ?...? позволяет вести поиск в об- ратном направлении. Обратный поиск также циклический: дойдя до первой строки, редактор перейдет на конец буфера и продол- жит поиск в обратном направлении, пока не просмотрит все содержимое буфера.
52 Гл. 3. Редактирование файлов 3.1.4. Контекстное редактирование Редактирование текста путем добавления и удаления целых строк занимает много времени и часто приводит к ошибкам. Преобра- зование текста в пределах строки известно под названием «кон- текстное редактирование». Часть строки можно изменить, воспользовавшись запросом замены s (substitute — заменить). В результате выполнения запроса s/Fotran/ Fortran/ первое вхождение цепочки литер Fotran в текущей строке за- менится на цепочку Fortran. Вот несколько примеров использо- вания запроса замены: s/Fotran// Заменить цепочку Fotran пустой цепоч- кой, т. е. удалить ее. s/Fotran/Fortran/p Заменить первое вхождение Fotran на Fortran и распечатать отредактированную строку для проверки. + Is/Fotran/Fortran/ Заменить первое вхождение Fotran на Fortran в текущей и в следующей за ней строках. Запрос замены имеет тот же общий формат, что и ранее встре- чавшиеся запросы: начальная-строка, конечная-строка s/старый текст/новый текст/ или конкретная-строка s/старый текст/новый текст/ Если номера строк опущены, подразумевается текущая строка. При поисках по контексту искомая цепочка часто использу- ется как образец в запросе замены. Так бывает, например, когда нужно исправить орфографические ошибки или опечатки. При вводе запроса поиска /Fotran/ с последующей заменой s/Fotran/Fortran/ возможно сокращение: /Fotran/ редактор отвечает найденной строкой s//Fortran/
3,1. Редактор ed 53 Редактор хранит последний образец, использовавшийся в за- просе поиска или замены. После выполнения запроса замены s запрос // снова ищет очередное вхождение того же самого образ- ца. Если встретилась не та строка, которая требуется, можно снова применить запрос // для поиска следующей строки по тому же самому образцу. Глобальная замена Простое применение запроса замены, например s/ Fotran/ Fortran/ заменит в текущей строке только первое вхождение Fotran на Fortran. Запрос s/ Fotran/ Fortran/g заменит все вхождения Fotran в текущей строке. Модификатор g означает глобальную замену во всей строке. Можно использовать также и модификатор р. Запрос s/ Fotran/ Fortran/gp выполнит глобальную замену и распечатает отредактированную строку. Запрос 1, $s/F ot ran/ Fortran/g заменит все вхождения цепочки Fotran в буфере на Fortran. При поиске по контексту иногда полезно указывать, что искомая цепочка находится в начале или в конце строки. В образцах начало и конец строки обозначаются литерами Л и $ соответ- ственно. Примеры: / А At/ Найти следующую строку, начинающуюся с At. /};$/ Найти следующую строку, оканчивающую- ся литерами};. /Л$/ Найти следующую пустую строку. /AUnix$/ Найти строку, содержащую только слово Unix. Такие же образцы можно использовать и в запросах замены (в роли заменяемой цепочки). s/A/The /р Вставить слово The в начало текущей стро- ки и распечатать ее. 4s/$/;/ Добавить литеру ; в конец четвертой строки. /А U NIX$/s//Unix/ Найти следующую строку, содержащую только слово UNIX и заменить эти четыре литеры на Unix.
54 Гл. 3. Редактирование файлов Запрос аннулирования Если запрос замены был выполнен ошибочно, запрос аннули- рования u (undo — аннулировать) вернет строку к ее первона- чальному виду. Этот запрос применим только к самой последней замене. 3.1.5. Сопоставление с образцом В образцах, используемых для поиска или замены, некоторые литеры имеют специальные значения. Эти литеры рассматри- ваются ниже. Литера точка Точка сопоставляется с любой литерой, так что по запросу /х.у/ будет найдена первая строка, содержащая цепочку литер типа х+у, х—-у, х=у. Литера звездочка Звездочка обозначает повторение литеры и используется, когда надо найти несколько (нуль или более) вхождений литеры. С об- разцом /.*;/ сопоставляется (в пределах одной строки) весь текст вплоть до последней точки с запятой включительно. Сопоставле- ние осуществляется с цепочкой максимально возможной длины, так что, если точка с запятой встречается в строке более одного раза, в сопоставленную цепочку войдут все ее вхождения. На- пример, запрос s/.*;// удаляет из строки все литеры вплоть до последней точки с за- пятой включительно. Запрос s/(.*)// удаляет первую левую скобку, последнюю правую скобку и все литеры между ними. Сопоставленные скобки не обязательно яв- ляются парными. Следует различать случаи употребления литеры * в редакторе и в командном языке оболочки. Использование литеры * в команд- ном языке аналогично использованию комбинации .* в редак- торе. Еще один пример. Запрос /а.*Ь/ будет искать строку, содержащую литеры а и b в этом порядке, разделенные, возможно, другими литерами.
3.1, Редактор ed 55 Квадратные скобки Квадратные скобки задают группы литер. Как и в командном языке, сопоставляется одна литера из группы. Задание группы литер иллюстрируется следующими примерами: Сопоставляется с любой из литер;, : или , . [а—z] Сопоставляется с любой строчной буквой от а до z. [А—Н] Сопоставляется с любой из прописных букв от А до Н включительно. [О—9] Сопоставляется с любой цифрой. [Л0—9] Литера л, если она стоит в группе первой, обозначает дополнение. Данный образец сопо- ставляется с любой литерой, кроме цифры. 1.\$*Л[] Сопоставляется с любой специальной литерой. В группах особо трактуются только литеры Л и ]. Чтобы включить в группу литеру ], ее сле- дует указать в списке первой. Чтобы вклю- чить в группу литеру Л, ее следует поместить в любую позицию списка, кроме первой. Следующие примеры поясняют использование образцов в за- просах замены: 1,$s/a[0—91*// Удалить все цифры в начале каждой l,$s/10—91*$// строки. Удалить все цифры в конце каждой s/[.\$*All// строки. Удалить из текущей строки первое вхож- S/, e\.g\..*/7 дение любой специальной литеры. Заменить текст, начиная с , e.g. до конца строки, на точку. Выделение части образца Часть образца, используемого в запросах поиска или замены, можно выделить, заключив ее в скобки \(и \). Например, запрос /\(.*\)ф\(.*\)/ будет искать строку, содержащую литеру табуляции (изобра- женную здесь как ф). Две подцепочки, заключенные в скобки \(...\), можно использовать в заменяющей цепочке запроса замены, например так: з//\2ф\17
56 Гл. 3. Редактирование файлов Обозначения \1 и \2 именуют первую и вторую выделенные подцепочки. В этом примере два поля меняются местами. Если в строке встречается более одной литеры табуляции, то сопо- ставляется самая правая. Отмена специальных значений литер Приведенные ниже литеры в образцах трактуются особым об- разом: Л . $ [ * \ / Чтобы использовать их на правах обычных литер, необходимо помещать перед ними литеру\. Так, /\./ ищет следующую строку, содержащую точку, тогда как /./ ищет следующую строку, содержащую какую-нибудь литеру (т. е. следующую непустую строку). Напомним, что то же самое соглашение используется для литер стирания и отмены 41= и @. При вводе с терминала эти литеры имеют специальное значение, и при работе с редактором их следует набирать как\4^ и \@ соответственно. Для поиска строки, содержащей /, также требуется исполь- зовать литеру \. Так, запрос S/\//*/p заменит в текущей строке / на * и затем распечатает измененную строку. 3.1.6. Глобальное редактирование Глобальный запрос g отбирает строки по образцу и для каждой найденной строки выполняет некоторый другой запрос редакти- рования. Глобальный запрос можно использовать, например, для исправления повторяющейся орфографической ошибки или вся- кий раз, когда требуется сделать массовые замены. Запрос g имеет формат g/образец/запросы Например, запрос g/A{/.—ip ищет все строки, начинающиеся с {, и печатает строки, пред- шествующие им. Как и в других запросах, диапазон действия запроса g можно ограничить. Так, l,20g/Achapter/s/c/C/
3.1. Редактор ed 57 выполнит запрос s/c/С/ для всех тех строк среди первых двадцати, которые начинаются со слова chapter. Когда нужно выполнить несколько запросов, перед каждой литерой «новая строка» сле- дует поместить литеру \. Например, запрос g/Achapter/s/c/C/\ лП1\ ищет строки, начинающиеся со слова chapter, заменяет в них слово chapter на Chapter и вставляет перед ними строку, содержа- щую текст .till. Все строки, кроме последней, должны закан- чиваться литерой\. Глобальный запрос не может содержать другой глобальный запрос. Запрос v аналогичен запросу g, за исключением того, что он отбирает строки, которые не сопоставляются с заданным образ- цом. Например, запрос v/A\./d исключает все строки, не начинающиеся с точки. 3.1.7. Другие возможности Прерывание и зависание При прерывании, вызванном нажатием клавиши del, редак- тор прекращает выполнение текущего действия и переходит к чтению следующего запроса. Этим можно воспользоваться, на- пример, для прерывания потока выдач от запроса печати вида g/-/P Если в процессе редактирования файла произошло зависание терминала, содержимое буфера сохраняется в файле с именем ed.hup в текущем оглавлении. Для того чтобы сравнить содержи- мое файла ed.hup с исходным содержимым файла, редактировав- шегося в момент зависания, можно воспользоваться командой diff. Восстановить файл из частично отредактированной его версии ed.hup можно командой ср или mv. Ограничители Поиск по контексту задается при помощи конструкции /.../. Литера / часто используется как ограничитель цепочек в запросе замены. Однако в качестве ограничителя в запросе замены можно использовать и любую другую литеру (например, двоеточие)
58 Гл. 3. Редактирование файлов при условии, что все ее вхождения в данный запрос согласуются с форматом команды. Например: s: Fotran: Fortran: Если литеру-ограничитель требуется использовать внутри об- разца, перед ней следует поместить литеру \. Выполнение команды Чтобы выполнить команду, не выходя из редактора, можно вос- пользоваться запросом !, например: .’mail honey позвони мне по номеру х7419 В этом примере пользователю honey посылается сообщение и осуществляется возврат в редактор. Ни буфер, ни редактируемый файл не изменяются. Сокращения В выражениях, задающих адреса строк, допускается ряд со- кращений. • Знак + может быть опущен. К примеру, выражения .+4 и .4 имеют одинаковый смысл. Другим сокращением для .4-4 является 4-4. • Знак — сам по себе означает сдвиг назад на одну строку. Выражение----------означает сдвиг назад на три строки и эквивалентно выражению .—3. • Выражение /. . ./— эквивалентно выражению /. . 1. Использование амперсанда В запросе замены s/abc/.../ литеру & можно использовать в заменяющем тексте для обозна- чения цепочки литер, сопоставленной с образцом. Например, запрос s/x4-y/(&)/ заключает выражение х4-у в круглые скобки.
3.1. Редактор ed 59 Неграфические литеры Запрос I аналогичен запросу р, за исключением того, что он за- меняет при выводе неграфические литеры (такие, как табуляция, шаг назад) комбинациями графических литер, как это показано ниже. (Представление неграфических литер различно в разных версиях редактора ed.) табуляция возврат на шаг обратная косая черта звонок перевод формата Если последними литерами в строке являются пробелы, за ними выводится комбинация \п: ...\п Объединение и разбиение строк Рассмотрим для примера строку текста ...abc... Чтобы вставить литеру новой строки между а и Ь, можно восполь- зоваться запросом замены, в котором для отмены специального значения этой литеры перед ней помещается \. Например, запрос s/ab/a\ Ь/ вставляет литеру новой строки между а и Ь. Один запрос занимает две строки. И наоборот, две строки, например if х==у && y==z можно объединить в одну. Если текущей является первая из этих двух строк, то запрос j объединит обе строки в одну и сделает ее текущей. В общем случае можно объединить целую группу смежных строк. Например, запрос 1,4jp объединяет в одну строку строки с 1-й по 4-ю включительно и печатает получившуюся строку. Маркировка строк Запрос номер-строки кх
60 Гл. 3. Редактирование файлов помечает указанную строку (по умолчанию — текущую) меткой х. В качестве меток могут использоваться любые строчные (латин- ские) буквы. На помеченные строки можно ссылаться при по- мощи конструкции, состоящей из одиночной кавычки и метки: 'х Запросы Е, Q и W Запросы е и q выведут литеру ?, если результаты редактирования не были записаны в какой-нибудь файл. Запрашиваемое действие в этом случае не выполняется. Защита отключается, если исполь- зуются команды Е и Q. Эти команды следует применять осторож- но, так как при небрежном их использовании можно потерять результаты целого сеанса редактирования. Запрос w записывает содержимое буфера в файл, полностью исключая прежнее содержимое этого файла. Для того чтобы до- писать информацию в конец файла, не уничтожая его старое со- держимое, можно воспользоваться запросом W. 3.2. РЕДАКТОР vi Освоив редактор ed, пользователи вскоре осознают и свойствен- ную ему ограниченность. Этот редактор был разработан в те времена, когда использовались медленные механические терми- налы, такие, как телетайпы моделей 33 и 37 фирмы Teletype. Экраны современных дисплеев вмещают по крайней мере 24 стро- ки по 80 литер каждая. На работу с такими устройствами и рас- считан редактор vi. Наилучший эффект достигается, когда терми- налы работают со скоростью 9600 бод, но имеет смысл исполь- зовать vi и при скорости 1200 бод. При меньших скоростях лучше использовать редактор ed. Редактору vi необходимо знать тип используемого терминала. Тип терминала задается установкой переменной среды TERM. На командном языке оболочки это записывается, например, так: TERM=2621 export TERM Значение, присваиваемое переменной TERM, зависит от типа терминала (в данном примере это устройство 2621 фирмы Hewlett Packard). Если имя типа терминала неизвестно, можно присвоить пере- менной TERM значение dumb. В этом случае редактор vi будет работать с любым терминалом, но экранные средства, которыми как раз привлекателен редактор vi, использоваться не будут. По команде vi pgm.c
3.2. Редактор vi 61 на экране появится несколько первых строк файла pgm.c, после чего можно вводить запросы редактирования. Появление на эк- ране странных литер свидетельствует, по всей видимости, о том, что тип терминала (значение переменной TERM) был установлен неправильно, или же переменная TERM не экспортирована из оболочки. Запрос :q, завершаемый возвратом каретки, осуществ- ляет выход из редактора. Запрос :q! соответствует запросу Q редактора ed: выход из редактора произойдет, даже если теку- щее содержимое буфера не было записано в файл. В отличие от редактора ed запросы редактора vi состоят из одной или более литер, причем некоторые (но не все) запросы должны оканчиваться литерой возврата каретки или esc. Если тип терминала установлен должным образом, сразу ста- новятся заметны отличия редактора vi от редактора ed. Некото- рые запросы исполняются немедленно и не выводятся на экран. Другие запросы появляются в нижней части экрана. Выводятся содержательные сообщения об ошибках, а не знак ?, как в ре- дакторе ed. Эти сообщения появляются также в нижней части экрана. 3.2.1. Управление окном Редактор vi устроен таким образом, что текст, который вы ви- дите на экране, представляет собой содержимое части буфера. Экран играет роль окна, через которое можно видеть содержимое буфера. Для продвижения окна вперед по буферу используются следующие запросы: AF продвигает окно на целую страницу (т. е. размер окна), AD продвигает окно на половину страницы. Обозначение ЛЕбыло введено в гл. 2 и означает управляющее F. Для продвижения по буферу в обратном направлении исполь- зуются запросы: ЛВ продвигает окно на целую страницу, AU продвигает окно на половину страницы. При достижении конца буфера вместо недостающих строк выво- дится литера ~. Теперь обратите внимание на курсор. В некоторых термина- лах он мерцает, в других — высвечивается в негативном изобра- жении. Курсор отмечает текущую позицию внутри буфера. 3.2.2. Управление курсором В процессе редактирования можно установить курсор в требуе- мую позицию на экране. Строка, содержащая курсор, является текущей. Положение курсора используется также в запросах
62 Гл. 3. Редактирование файлов редактирования. Управление курсором осуществляется при по- мощи следующих запросов: пробел Сдвиг курсора вправо на одну позицию, возврат на шаг Сдвиг курсора влево на одну позицию, возврат каретки Установить курсор на начало следующей строки. + Действует как «новая строка». — Установить курсор на начало предыдущей строки. $ Установить курсор в конец текущей строки. Имеется и ряд других запросов для перемещения курсора. При необходимости эти запросы выполняют и продвижение окна. За- прос /образец/ осуществляет поиск по образцу в прямом направлении и уста- навливает курсор на следующее встретившееся в буфере вхожде- ние этого образца. Как и в редакторе ed, для поиска в обратном направлении используется конструкция ?...? . Для того чтобы установить курсор на произвольную строку буфера, можно воспользоваться запросом G. Этот запрос, состоя- щий из номера строки и буквы G, установит курсор на строку буфера с заданным номером. По умолчанию, подразумевается последняя строка буфера, поэтому команда G установит курсор на конец буфера. Можно перемещать курсор по строке вперед или назад сразу на целое слово. Если при этом в текущей строке слов не оста- лось, курсор перемещается соответственно на следующую или предыдущую строку. w Установить курсор на начало следующего слова, b Установить курсор на начало предыдущего слова, е Установить курсор на конец текущего слова. В этих запросах словом считается последовательность из букв, цифр и знаков подчеркивания. В вариантах W, В и Е этих за- просов (т. е. когда имя команды задается прописной буквой) словом считается любая последовательность литер, не содержа- щая пробелов и табуляций. Это позволяет перемещать курсор че- рез знаки препинания и другие не буквенно-цифровые литеры. Перед всеми этими запросами можно задать коэффициент кратно- сти. Например, по запросу 3w курсор продвинется вперед на 3 слова.
3.2. Редактор vi 63 3.2.3. Вставки и удаления Можно вставлять или удалять текст в том месте, где находится курсор. Чтобы удалить одну литеру, наберите х, а для удаления следующих трех литер наберите Зх. Вставка текста осуществляет- ся при помощи запросов i и а. Запрос вставки I (insert — вста- вить), например, записывается в виде i... esc где многоточие означает вводимый текст, a esc — клавишу escape (авторегистр 2) на терминале. Текст вставляется непосредственно перед курсором и может содержать произвольное количество строк. Вставка текста продолжается до тех пор, пока не будет нажата клавиша esc. Запрос а начинает вставку текста с позиции за (а не перед) курсором и имеет вид a...esc Прежде чем продолжить описание запросов редактора vi, стоит заметить, что в vi можно использовать любой запрос редактора ed. Для этого надо ввести двоеточие и за ним — запрос редактора ed. Например, для выхода из редактора vi наберите запрос :q, а для записи содержимого буфера назад в файл и выхо- да — запрос :wq. Если в буфер были внесены изменения, вы не сможете выйти из редактора при помощи запроса :q, пока не запишите содержимое буфера в файл. Если у вас нет права записи в файл, редактор выдаст сообще- ние об этом, и запись выполнена не будет. 3.2.4. Редактирование строк Для вставок текста внутри строки можно использовать запросы i и а. Добавление новых строк удобнее выполнять с помощью запроса о: о esc который вставляет текст ... строка за строкой после текущей строки. Запрос О выполняет аналогичные действия, но вставляет текст перед текущей строкой. Имеются разнообразные запросы, позволяющие удалять текст из редактируемого документа: х Исключить текущую литеру. dd Исключить текущую строку. dw Исключить текущее слово.
64 Гл. 3. Редактирование файлов D Исключить остаток текущей строки. гс Заменить текущую литеру на литеру с. Перед большинством команд можно задавать коэффициент крат- ности. Запрос 3dd исключит 3 строки, начиная с текущей. 3.2.5. Пересылка текста Переслать текст из одного места в другое можно, сначала удалив его, а затем поместив в новое место при помощи запроса р (put — поместить). Запрос р помещает исключенный текст в место, ука- зываемое курсором. Если были исключены целые строки, то они вставляются вслед за текущей строкой; если же было исключено несколько литер в пределах строки, то эти литеры вставляются вслед за текущей литерой. Вот пример типичной последователь- ности действий: /main/ Найти цепочку main. 4dd Исключить 4 строки. 3+ Продвинуться вперед на 3 строки. р Поместить 4 исключенные строки вслед за новой текущей строкой. Если несколько литер были исключены запросом х, запрос р поместит их за текущей литерой; поэтому, например, запрос хр поменяет местами текущую и следующую за ней литеры. Исклю- ченный текст можно поместить перед текущей строкой или перед текущей литерой при помощи- запроса Р. Если при редактировании допущена ошибка, ее можно ис- править при помощи запроса и, который аннулирует последнее сделанное в буфере изменение. Аннулировать все изменения, сделанные в текущей строке, можно, воспользовавшись запро- сом U. Этот запрос, однако, не сработает, если вы перейдете на другую строку, а потом вернетесь назад, даже если при этом вы не выполните никаких редактирующих действий. Исключенный текст можно восстановить при помощи запроса р или Р. Можно восстановить до 9 фрагментов текста, исключен- ных последними. Например, запрос "5р возвратит в буфер текст, удаленный пятым по счету запросом исключения (счет ведется от последнего запроса). Запрос . повторяет последнее редактирующее действие, по- этому dd . . . исключит 4 строки. Для копирования строк можно воспользоваться запросом Y* В примере Yp
3.2. Редактор vi запрос Y скопирует текущую строку в специальный скрытый буфер, а запрос р поместит эту копию вслед за текущей строкой. 3.2.6. Сводка запросов Подведем итог. На первое время для работы с редактором vi достаточно знать перечисленные ниже запросы. Эти запросы позволяют вставлять и исключать текст, записывать результаты редактирования в файл и выходить из редактора. Ими следует овладеть до чтения следующего раздела. AD Продвинуть-бкно вперед. Л11 Продвинуть окно назад. AF Продвинуться вперед на страницу. АВ Продвинуться назад на страницу. возврат каретки Переместить курсор вниз. — Переместить курсор вверх. пробел Сдвинуть курсор вправо. возврат на шаг Сдвинуть курсор влево. dd Исключить текущую строку. i Вставить текст перед текущей литерой. о Вставить текст вслед за текущей строкой. р Вставить исключенный или скопированный текст. х Исключить текущую литеру. Y Скопировать группу строк в скрытый буфер. :w file Записать отредактированный текст в файл file. :q Выход из редактора. Команда :q! осущест- вляет выход, не проверяя, сохранен ли редактировавшийся текст. del Прервать выполнение текущей команды. 3.2.7. Дополнительные возможности Изучить описанные выше запросы можно за несколько сеансов работы за терминалом. В данном разделе описываются средства, полезные при частом использовании редактора. Управление курсором и окном Н Установить курсор на первую строку экрана. L Установить курсор на последнюю строку экрана. М Установить курсор на середину экрана. hjkl Сдвинуть, курсор влево, вниз, вверх или вправо соответственно. wbe Установить курсор на следующее слово, на преды- дущее слово или на конец текущего слова. 3 С. Баурн
66 Гл. 3. Редактирование файлов /.../ ?...? Z. Поиск по образцу ... в прямом направлении. Поиск по образцу ... в обратном направлении. Сдвинуть изображение так, чтобы текущая строка оказалась в центре экрана. z вк Сдвинуть изображение так, чтобы текущая строка стала первой строкой экрана. ВК означает возврат каретки. Z п. Использовать окно из п строк. Окно размещается % в центре экрана. Установить курсор на следующую или предыдущую парную скобку ( , ), { или }. ЛЕ Сдвинуть изображение на экране на одну строку вперед. AL лу Восстановить изображение на экране. Сдвинуть изображение на экране на одну строку назад. О Установить курсор в начало строки. Запросы редактирования А... Вставить текст в конец текущей строки (вставляе- мый текст оканчивается авторегистром esc). С... Заменить остаток строки (заменяющий текст окан- чивается авторегистром esc). D Исключить остаток строки. I... Вставить текст в начало текущей строки (вставляе- мый текст оканчивается авторегистром esc). J Объединить текущую и следующую строки. X Удалить литеру перед курсором. cw... Заменить текущее слово (заменяющий текст окан- чивается авторегистром esc). гх Заменить текущую литеру на литеру х. ~ Изменить регистр текущей литеры. Прописная бук- ва заменяется строчной, строчная — прописной. & Повторить последний запрос замены :s. Использование запросов редактора ed В редакторе vi можно использовать запросы редактора ed, пред- варяя их двоеточием. Наиболее часто используются следующие запросы: :sh Вызвать программу-оболочку. :!cmd Выполнить команду cmd и вернуться в vi. :r file Считать файл file. :s... Заменить одну цепочку литер на другую. _ :g... Глобальный поиск по цепочке.
3.2. Редактор vi 67 Объекты В некоторых запросах параметром является объект. В запросе d, например, параметр-объект указывает, что нужно удалить. Если параметром является буква, совпадающая с именем запроса (например, dd), то запрос применяется к текущей строке. Выше уже встречались спецификации объектов. Например, в командах dw и cw буква w обозначает слово. Спецификация объектов происходит следующим образом: с Одна литера. w Следующее буквенно-цифровое слово. W Следующее слово, составленное из литер, отличных от пробела и табуляции. Н Верхняя первая строка в экране. ЗН означает тре- тью сверху строку в экране. L Последняя строка в экране. 3L означает третью снизу строку в экране. I ... / Следующая строка, содержащая образец ... . ) Конец текущего предложения. Предложение за- канчивается пустой строкой или одной из литер ., !, ?, за которой следует новая строка или два пробела. ( Начало текущего предложения. } Конец текущего абзаца. Абзац заканчивается пус- той строкой или одним из запросов форматора nroff: .bp, .IP, .LP, .PP, .QP, .LI, .P. { Начало текущего абзаца. .]] Конец текущего раздела. Раздел заканчивается одной из макрокоманд .NH, . SH, .HU или .Н фор- матора nroff. [[ Начало текущего раздела. Эти объекты используются как параметры в следующих командах: сх... Заменить текст вплоть до х включительно новым текстом, заканчивающимся авторегистром esc. dx Исключить текст вплоть до х включительно. ух Скопировать объект х для последующего исполь- зования в команде р или Р. >х Сделать отступ из 8 пробелов во всех строках вплоть до строки, содержащей х, включительно. <Zx Устранить отступ из 8 пробелов во всех строках вплоть до строки, содержащей х, включительно. lx cmd Заданный объект х передается команде cmd в ка- честве стандартного ввода. Команда выполняется, и объект замещается ее стандартным выводом. з*
68 Гл. 3. Редактирование файлов Например, по команде ! Idate текущая строка заменяется выводом команды date. Команда ! }sort вызовет утилиту сортировки sort, передав ей в качестве стандарт- ного ввода очередной абзац текста, и заменит этот абзац отсор- тированным выводом. Коэффициенты Число, предшествующее команде, является коэффициентом крат- ности выполнения команды, за исключением следующих случаев: новый размер окна [[ ]] : / ? величина, на которую продвигается окно AD AU номер строки или столбца z G | Редактирование совокупности файлов В vi имеется возможность редактировать совокупность файлов. Когда vi вызывается командой vi файл ... то сначала в буфер считывается первый файл из списка. После того как он будет отредактирован, по команде :п в буфер считы- вается следующий файл. Если содержимое буфера не было сохра- нено, выводится сообщение об ошибке, и команда не выполняет- ся. Сообщение об ошибке выводится также и в ответ на запрос выхода :q — команда не выполняется до тех пор, пока не будут отредактированы все файлы из заданного списка. При помощи команды :set (см. ниже) можно, однако, установить режим autowrite — автоматической записи буфера в файл. Нейтрализация сбоев Под сбоем системы понимается аппаратная или программная ошибка, повлекшая за собой перевызов системы. Хотя это слу- чается и не часто, редактор vi защищает пользователя от потери сеанса редактирования, сохраняя копию буфера в некотором файле. Копия буфера сохраняется и в случае, если в процессе редактирования произошло зависание терминала. В любом случае редактор пытается оставить для вас почтовое сообщение, содержащее имя редактировавшегося файла и описание способа его восстановления. Файл можно восстановить, задав при вызове
3.2. Редактор vi 69 редактора опцию —г. Если, например, в момент сбоя редакти- ровался файл с именем precious, то по команде vi —г precious считается сохраненная копия буфера, и редактирование возоб- новится с прерванного места. В зависимости от того, в какой мо- мент произошел сбой, возможна потеря операции редактирова- ния, выполнявшейся последней. Установка внутренних переменных Редактор vi имеет ряд внутренних переменных, определяющих различные режимы его работы. Текущие значения этих перемен- ных выводятся командой :set all Каждая переменная имеет имя и устанавливается при помощи одной из команд: :set имя-переменной :set имя-переменной = значение Соответствующий режим отменяется командой :set по имя-переменной Ниже приводится список имен внутренних переменных. В скоб- ках даются допустимые сокращения. autoindent(ai) Делать автоматические отступы в тексте про- граммы. autowrite(aw) Автоматическая запись буфера в файл перед выполнением команд :п и !. ignorecase(ic) При выполнении поиска не различаются list number(nu) прописные и строчные буквы. Выдавать литеры табуляции в виде Л1. Выдавать строки текста вместе с их номерами. paragraphs(para) Список имен макрокоманд форматора nroff, redraw(re) задающих начало абзаца (для запросов } и {). Начальное значение — IPLPPPQPbpP LI. Моделирование интеллектуального термина- ТТЯ sections(sect) l/ld • Список имен макрокоманд, задающих нача- ло раздела (для запросов [[ и ]]). Начальное значение— NHSHH HU. term Имя типа используемого терминала. Эти режимы можно также устанавливать автоматически, исполь- зуя переменную EXINIT программы-оболочки. Например, вы- полнение команд
70 Гл. 3. Редактирование файлов EXINIT-'set ai aw' export EX I NIT приводит к автоматической установке режимов автоотступа и автозаписи при входе в редактор. Определение новых запросов В редакторе vi предусмотрены простые макросредства, позво- ляющие заменять некоторую последовательность запросов одной литерой. Например, после выполнения запроса :тар = :. = луВК ввод литеры = становится эквивалентным вводу запроса . Литера AV отменяет специальное значение литеры возврат ка- ретки (ВК), завершающей запрос . В приведенном примере требуются две литеры ВК*. одна входит в определение, а вторая завершает собственно запрос :тар. Другой пример. После выполнения :тар ; easAVesc запрос ; будет добавлять букву s в конец текущего слова. Ли- тера AV снова используется для отмены специального значения, на этот раз авторегистра esc. Ниже перечислены литеры, с которыми в редакторе vi не связано никаких действий. Эти литеры являются кандидатами на роль имен новых команд, определяемых посредством :тпар i KV.gqvt;_*«
ГЛАВА 4 ОБОЛОЧКА Оболочка (shell) является одновременно и языком программиро- вания, и командным языком. Оболочку часто называют также интерпретатором команд системы UNIX. Существует определен- ное сходство между оболочкой системы UNIX и интерпретато- рами команд в системах Cambridge Multiple Access System и CTSS: форма записи простейших команд и конструкции для передачи и подстановки параметров в командных языках всех этих систем аналогичны. Как командный язык оболочка обеспечивает интерфейс поль- зователей с операционной системой UNIX. Оболочка выполняет команды, поступающие либо с терминала, либо из файла. Поль- зователь может строить свои собственные команды, создавая командные файлы (т. е. файлы, состоящие из команд). Такие вновь созданные команды могут иметь параметры и обладают тем же статусом, что и «системные» команды, содержащиеся в оглав- лениях /bin и /usr/bin. Таким образом можно построить новую операционную среду, отвечающую потребностям отдельного поль- зователя или группы пользователей. При разработке оболочки, поэтому, учитывалась возможность ее использования как в интерактивном, так и в неинтерактивном режимах. За исключением нескольких несущественных деталей, функционирование оболочки не зависит от типа источника ввода. Как язык программирования оболочка предоставляет пере- менные, значениями которых являются цепочки литер, и управ- ляющие конструкции, в том числе ветвление и итерацию. Язык ориентирован на то, чтобы им было удобно пользоваться при работе за терминалом, поэтому цепочки литер в нем обычно не заключаются в кавычки. В качестве цепочки литер может исполь- зоваться вывод любой команды. Это позволяет использовать команды для выполнения арифметических операций и других действий, не предусмотренных в оболочке. Команды оболочки подобны вызовам функций в языках про- граммирования типа С. Однако в форме записи имеются два
72 Гл. 4. Оболочка отличия. Во-первых, хотя параметрами команд являются произ- вольные цепочки литер, в большинстве случаев не требуется за- ключать их в кавычки. Во-вторых, список параметров не заклю- чается в скобки, и параметры не отделяются друг от друга запя- тыми. Тенденцией развития командных языков является отказ от сложного синтаксиса выражений, характерного для языков программирования типа С. Командный язык предназначен в пер- вую очередь для того, чтобы вводить команды; важно, чтобы он был свободен от избыточных литер. 4.1. КОМАНДНЫЕ ПРОЦЕДУРЫ В гл. 2 было показано использование оболочки в интерактивном режиме. В этой главе оболочка рассматривается как язык про- граммирования, и теперь мы опишем, как создавать новые команды. Оболочку можно использовать для чтения и выполнения команд, содержащихся в некотором файле. Например, команда sh файл [ параметр ... ] вызывает программу-оболочку для чтения команд из указанного файла. Такой файл называется командным файлом или командной процедурой. При вызове могут быть заданы параметры. В команд- ном файле на них можно ссылаться, используя позиционные па- раметры $1, $2,... . Например, если файл wg содержит команду who I grep $1 то вызов процедуры sh wg fred эквивалентен выполнению команды who | grep fred Файлы в системе UNIX имеют три независимых атрибута: чтения, записи и выполнения. Чтобы сделать файл выполнимым, можно воспользоваться командой chmod (подробные сведения об этой команде приводятся в разд. 6.3.2). Например, команда chmod +х wg сделает файл wg выполнимым. После этого команда wg fred будет эквивалентна команде sh wg fred
4.1. Командные процедуры 73 Таким образом обеспечивается взаимозаменяемость командных процедур и программ. В любом случае для выполнения команды создается новый процесс. Наряду с именами позиционных параметров можно исполь- зовать и количество позиционных параметров в вызове — $4Н- Имя выполняемого файла доступно как $0. Специальный параметр $* языка-оболочки используется для подстановки всех позиционных параметров, кроме $0. Обычно $* используется при задании некоторых стандартных парамет- ров. Так, в примере nroff —Т450 —ms $* к уже заданным просто добавляются некоторые другие параметры. Командные процедуры можно использовать для перестраи- вания операционной среды с учетом привычек и потребностей группы пользователей или отдельного пользователя. Поскольку такие процедуры представляют собой текстовые файлы и не тре- буют компиляции, их создание и сопровождение не вызывает никаких затруднений. 4.1.1. Управляющая конструкция for Командная процедура часто представляет собой цикл по пара- метрам $1, $2, ... . Команды цикла выполняются один раз для каждого из параметров. Примером такой процедуры является tel, которая просматривает телефонный справочник в файле /usr/lib/telnos, содержащем строки вида fred mhO 123 bert mh0789 Процедура tel имеет вид for i do grep $i /usr/lib/telnos done Команда tel fred напечатает строки из файла /usr/lib/telnos, содержащие слово fred. А по команде tel fred bert будут распечатаны сначала строки, содержащие слово fred, а затем строки, содержащие слово bert.
74 Гл. 4. Оболочка Цикл for распознается оболочкой и имеет следующий общий вид: for имя in wl w2 ... do список-команд done Список-команд — это последовательность из одной или несколь- ких простых команд, которые разделяются точкой с запятой или заканчиваются литерой новой строки. Кроме того, зарезерви- рованные слова, такие, как do или done, обычно должны следо- вать за литерой новой строки или точкой с запятой. Список зарезервированных слов приведен в приложении 6. Имя — это переменная оболочки, принимающая по очереди значения wl, w2, ... при каждом выполнении следующего за do списка- команд. Если конструкция in wl w2... опущена, то тело цикла выполняется один раз для каждого позиционного параметра, т. е. подразумевается in $*. Другим примером использования цикла for является команда create, текст которой имеет вид for i do >$i; done Команда create alpha beta создает два пустых файла: alpha и beta. Конструкцию >файл саму по себе можно использовать для создания файла или унич- тожения его содержимого. Обратите внимание также на то, что перед словом done требуется точка с запятой (или литера новой строки). Для проверки существования файла можно использо- вать и конструкцию <файл. 4.1.2. Управляющая конструкция case Конструкция case предназначена для организации ветвления программы по нескольким направлениям. Например, команда append имеет вид case 1п 1) cat >>$1 ;; 2) cat >>$2 <$1 ;; * ) echo 'usage: append [ from J to' ;; esac При вызове с одним параметром append file
4.1, Командные процедуры 75 значением $=Н= является цепочка, состоящая из литеры 1, и стан- дартный ввод копируется в конец файла file при помощи коман- ды cat. Команда append filel file2 добавляет содержимое файла filel к содержимому file2. Если количество параметров в команде append отлично от 1 или 2, то выдается сообщение о том, как пользоваться командой («ис- пользование: .append [ из ] в»). Общий вид команды case следующий: case слово in образец) список-команд ;; esac Каждая альтернатива заканчивается литерами Литеры ;; перед esac можно опускать. Оболочка пытается сопоставить указанное слово с каждым из образцов в порядке йх записи. Если найден подходящий об- разец, выполняется соответствующий список-команд, после чего выполнение конструкции case завершается. Поскольку образец * сопоставляется с любой цепочкой литер, его можно исполь- зовать, когда требуется выполнить некоторые действия для «всех остальных» случаев. Предостережение. Не делается никакой проверки на то, что слову, заданному в case, соответствует только один образец. Выполняемый набор команд определяется по первому сопоста- вившемуся образцу. В приведенном ниже примере команды, сле- дующие за второй звездочкой, никогда не выполнятся. case $# in • )... ;; * ) ... ;; esac Конструкцию case можно использовать для распознавания различных видов параметров. Следующий пример представляет собой фрагмент команды сс1>: for i do case $i in — Iocs]) ... ;; — «) echo 'unknown flag $i' ;; * .c) /lib/сО $i ... ;; * ) echo 'unexpected argument $i' ;; done i> Команды echo в этом фрагменте используются для вывода сообщений об ошибках.— Прим, перёй.
76 Гл. 4. Оболочка В конструкции case можно связать один и тот же набор команд с несколькими образцами. Такие альтернативные образцы разде- ляются литерой |. Например, case $i in —х|—у) ... esac эквивалентно case $i in —[xy]) ... esac Используются обычные соглашения об отмене специальных зна- чений литер, поэтому в примере case $i in \?) ... esac будет выполнено сопоставление с литерой ?. 4.1.3. Встроенные документы Командная процедура tel, описанная в разд. 4.1.1, использует в качестве источника данных для команды grep файл /usr/lib/telnos. Другой способ состоит в том, чтобы включить эти данные в саму процедуру в виде встроенного документа: for i do grep $i <<! fred mhO 123 bert mh0789 ! done В этом примере в качестве стандартного ввода для команды grep берутся строки, заключенные между «! и !. Встроенный документ заканчивается строкой, содержащей цепочку литер, заданную после «, поэтому вместо литеры I может быть исполь- зована любая другая литера. Прежде чем встроенный документ станет доступен команде grep, в нем выполняется подстановка значений параметров. Это иллюстрируется на примере процедуры edg (рис. 4.1). Вызов edg string 1 string2 file
4.1. Командные процедуры 77 эквивалентен команде ed file «% g/stringl/s//string2/g w % . и приводит к замене всех вхождений цепочки литер string! в файле file на цепочку string2. Если содержимое буфера было записано в файл, команда выхода из редактора ed не обязательна, достаточно признака конца файла. ed $3 «% fl/Я/е//$2/д w % Рис. 4.1 Процедура edg Подстановку значения параметра можно предотвратить, ис- пользуя литеру \ для отмены специального значения литеры $, как, например, это делается в другом варианте команды edg: ed $3 << + l,\$s/$l/$2/g w + Этот вариант команды edg эквивалентен первому с той лишь разницей, что редактор ed будет печатать знак ?, если в файле нет ни одного вхождения цепочки $1. Подстановку значений параметров во встроенный документ можно отменить вообще, задав отмену специальных литер при указании завершающей це- почки литер, например: grep $i «\: Здесь встроенный документ передается команде grep без каких- либо изменений. Если во встроенном документе не требуется выполнять подстановку значений параметров, то последняя фор- ма записи более эффективна. 4.1.4. Переменные оболочки В оболочке допускаются переменные, значениями которых яв- ляются цепочки литер. Имена переменных начинаются с буквы и состоят из букв, цифр и литер подчеркивания. Переменным
78 Гл. 4. Оболочка можно присваивать значения, например: user=fred box=m000 acct=mhOOOO В этом примере присваиваются значения переменным user, box и acct. По обе стороны от знака = пробелы не допускаются. Переменной можно присвоить пустую цепочку, например: TERM= Для подстановки значения переменной перед ее именем указы- вается литера $. Например, команда echo $user выведет слово fred. Переменные можно использовать при работе в интерактивном режиме как сокращения для часто используемых цепочек литер. Например, b=/usr/fred/bin mv pgm $b выполнит пересылку файла pgm из текущего оглавления в оглав- ление /usr/fred/bin. Для подстановки значений параметров (или переменных) существует более общая форма записи. Например, команда echo ${user} эквивалентна команде echo $user Такая форма записи используется, когда за именем переменной следует буква или цифра. Например, tmp=/tmp/ps ps a >${tmp}a направит вывод команды ps в файл /tmp/psa, тогда как ps a >$tmpa привела бы к подстановке значения переменной tmpa. Специальные переменные За исключением переменной $?, все перечисленные ниже пере- менные устанавливаются программой-оболочкой в начале ее работы. Переменная $? устанавливается после выполнения каж- дой команды. $? Код ответа (статус завершения) последней выполнен- ной команды в виде цепочки десятичных цифр. Боль-
4,1. Командные процедуры 79 шинство команд возвращают нулевой код ответа, если их выполнение завершилось успешно, и ненулевой код в противном случае. Проверка значений кодов от- вета будет рассмотрена в разделе, где описываются конструкции if и while. $0 Имя выполняемой командной процедуры. Одна и та же команда может быть вызвана под разными име- нами. Переменная $0 позволяет различать эти слу- чаи. Например, приведенный ниже фрагмент входит в процедуру ttytek; кроме того, на тот же самый файл существует ссылка ttyblit. Если на файл делается но- вая ссылка и он вызывается под новым именем, вы- полняется последовательность действий, предусмот- ренная для всех остальных случаев. Эта команда ус- танавливает параметры терминала при помощи ко- манды stty case $0 in ttyblit) stty erase ЛН kill @ ffO tabs ;; ttytek) stty erase ЛН kill @ tek —tabs ;; *) stty erase ЛН kill @ ;; esac $Ф Количество позиционных параметров (в десятичном виде). Используется, например, в команде append (разд. 4.1.2) для проверки числа заданных параметров. Значение переменной также переустанавливается при выполнении команды set. $$ Номер процесса, в рамках которого выполняется дан- ная оболочка (в десятичном виде). Поскольку номера всех процессов уникальны, эту переменную часто ис- пользуют для генерации имен временных файлов. Например: ps a >/tmp/ps$$ rm /tmp/ps$$ $! Номер последнего фонового процесса (в десятичном виде). $— Флаги программы-оболочки, такие, как —х и —v, установленные на данный момент. Некоторые переменные имеют для оболочки особое значение, их не следует использовать для других целей. Эти переменные обычно устанавливаются во входном файле .profile в регистра- ционном оглавлении пользователя. $MAIL При работе с терминалом оболочка перед выда- чей очередного приглашения обследует состоя- ние файла, определяемого этой переменной.
80 Гл. 4. Оболочка $НОМЕ SCDPATH $РАТН Если с момента предыдущего обследования в этот файл были внесены изменения, оболочка выведет сообщение you have mail (для вас есть почта) перед выдачей приглашения для ввода очередной команды. Например, для пользователя fred эта переменная устанавливается следующим образом: МА IL=/usr/spool/mail/fred Подразумеваемое значение параметра для команды cd. Имена файлов, которые не начинаются с лите- ры /, считаются именами относительно текущего оглавления. Текущее оглавление можно сменить командой cd. Например, команда cd /usr/fred/bin сделает текущим оглавление /usr/fred/bin. Ко- манда cd без параметров эквивалентна команде cd $НОМЕ Список оглавлений, просматриваемых командой cd. Имена оглавлений разделяются двоеточиями. Типичная установка этой переменной выглядит так: CDPATH$HOME/desk В соответствии со значением этой переменной cd будет просматривать текущее оглавление, роди- тельское оглавление (обозначенное..), и, наконец, оглавление $HOME/desk. Например, если су- ществует оглавление ../src и в текущем оглав- лении нет оглавления src, то команда cd src сделает текущим оглавление ../src и выведет это имя в качестве подтверждения. Список оглавлений, содержащих команды {путь поиска). Каждый раз, когда требуется выполнить коман- ду, оболочка ищет соответствующий выполни- мый файл в заданном списке оглавлений. Если переменная $РАТН не установлена, то, по умолчанию, поиск ведется в текущем оглавле- нии, оглавлениях /bin и /usr/bin. Значением переменной $РАТН является последователь- ность имен оглавлений, разделенных двоето- чиями. Например, PATH=.:./bin:$HOME/bin:/bin:/usr/bin задает следующий порядок просмотра оглавле- ний: текущее оглавление (литера . перед первым
4.1. Командные процедуры 81 двоеточием), оглавления ./bin, $HOME/bin, /bin и /usr/bin. Таким образом, отдельные поль- зователи могут хранить свои собственные коман- ды в оглавлении $HOME/bin и пользоваться ими независимо от того, какое оглавление яв- ляется текущим. Оглавление ./bin включено в список для того, чтобы можно было использо- вать команды из подоглавления bin текущего оглавления (если такое оглавление существует). Это позволяет отделять команды от файлов с дан- ными внутри одного оглавления, связанного с конкретной тематикой. Если имя команды содержит литеру /, просмотр оглавлений не производится; делается единст- венная попытка выполнить команду. Форму записи ./cmd можно использовать для того, чтобы не выполнять поиск по оглавлениям, если команда находится в текущем оглавлении. $PS1 Текст основного приглашения оболочки; по умолчанию — $. $PS2 Оболочка выдает приглашение $PS2, если тре- буется продолжить ввод команды; по умолчанию используется литера >. $IFS Набор литер, которые интерпретируются как пробелы (см. разд. 4.2.4). 4.1.5. Команда test Команда test предназначена для использования в командных процедурах. В некоторых версиях программы-оболочки для по- вышения эффективности команда test реализована как встроен- ная функция. Например, команда test —f file возвращает нулевой код ответа, если файл file существует, и не- нулевой код ответа в противном случае. В общем случае test вычисляет некоторый предикат и возвращает полученный результат в виде кода ответа. Вот некоторые из наиболее часто используемых в команде test параметров: test s Истина, если параметр s не является пустой це- почкой литер. test —f file Истина, если файл file существует и не является оглавлением. test —г file Истина, если файл file доступен для чтения.
82 Гл. 4. Оболочка test —w file Истина, если файл file доступен для записи, test —d file Истина, если файл file является оглавлением. В оболочке отсутствуют средства для выполнения арифмети- ческих операций, однако эти операции доступны косвенно через команду ехрг. 4.1.6. Управляющие конструкции while и until Действия, выполняемые циклом for и ветвлением case, зависят от значений переменных оболочки. Имеются также циклы while и until и ветвление if then else; выполняемые ими действия определяются кодами ответа, возвращаемыми командами. Цикл while имеет следующий вид: while список-командх do сп и со к-ко манд 2 done Значением, проверяемым в цикле while, является код ответа последней из команд, следующих за словом while. При каждой итерации выполняется список-команда если возвращается нуле- вой код ответа, то выполняется список-команд2; в противном слу- чае выполнение цикла заканчивается. Например, цикл while test $1 do ... shift done эквивалентен циклу for i do ... done Команда shift (сдвиг) — это команда оболочки, которая переиме- новывает позиционные параметры $2, $3, ... в $1, $2, ... и от- брасывает $1. Если вместо слова while используется until, условие завер- шения цикла заменяется на противоположное. В следующем примере программа ждет, пока не будет создан файл file: until test —f file do sleep 300; done команды Условием завершения цикла является существование файла file. Каждая итерация цикла заключается в пятиминутном ожидании (300 секунд), после чего условие проверяется снова. (Предпо- лагается, что какой-нибудь другой процесс в некоторый момент создаст этот файл.)
4.1. Командные процедуры 83 4.1.7. Управляющая конструкция if Имеется общая условная конструкция ветвления вида if список-команд then список-команд else список-команд fi В этой конструкции проверяется значение, возвращаемое послед- ней простой командой, следующей за if. Часть else может отсут- ствовать. Поскольку эта конструкция заключена в скобки if ... fi, она может использоваться везде, где допускается ис- пользование простых команд, не вызывая двусмысленного тол- кования. Более того, отсутствует «висячее else», создающее трудности при интерактивном режиме работы. Команду if можно использовать в сочетании с командой test для проверки существования некоторого файла, например: if test —f file then * обработка файла else ф выполнение каких-либо иных действий fi Полный пример использования конструкций if, case и for приве- ден в разд. 4.1.10. Вложенные конструкции if вида if ... then ... else if ... fi fi можно записать с использованием расширенной конструкции if: if ... then ... elif fi В качестве примера на рис. 4.2 приведена команда dw, кото- рая рекурсивно просматривает дерево оглавлений и печатает имена обнаруженных файлов. Установка переменной PATH га- рантирует, что будут выполняться нужные команды. Путь поиска команды часто включает в себя текущее оглавление. За- дание явного пути поиска защищает команду dw от случайности встретить команду, также называемую dw или test в каком-либо подоглавлении.
84 Гл. 4. Оболочка Цикл for анализирует каждое имя в текущем оглавлении. Если файл с таким именем существует и не является оглавле- нием, то никаких действий не выполняется; если же это имя Р АТН= / bin; / usr/bin;$HOME /bin cd $1 Is -I for I- in • do if feet -f $1 then else dw $1 fi done Рис. 4.2 Команда dw оглавления, то для выдачи списка имен файлов из этого оглав- ления рекурсивно вызывается команда dw. Последовательность if команда] then команда2 fi можно также записать в виде команда] && команда2 Наоборот, в конструкции команда] II команда^ команда2 будет выполнена только в том случае, если выполнение команды] закончилось неудачно. В любом случае возвращаемым значением является код ответа последней выполненной простой команды. 4.1.8. Группировка команд Команды можно группировать двумя способами: { список-команд ; } или ( список-команд )
4,1. Командные процедуры 85 В первом случае просто выполняется список-команд. Во вто- ром случае список-команд выполняется с помощью отдельного процесса оболочки. Например, (cd х; rm junk) выполнит команду rm junk в оглавлении х, не изменяя текущее оглавление в вызывающей оболочке. Команды cd х; rm junk выполняют те же самые действия, но текущим оглавлением станет оглавление х. Исторически сложилось так, что круглые скобки являются такими же специальными литерами, как и | и ;, и распознаются в любом контексте, если только их специальное значение не от- менено. Фигурные скобки являются зарезервированными сло- вами, такими же как if и do, поэтому они распознаются, только когда следуют за литерой новой строки или за точкой с запятой. 4.1.9. Отладка командных процедур В оболочке предусмотрены два механизма, облегчающие отладку командных процедур. Первый из них приводится в действие в результате выполнения в самой процедуре команды set —V (флаг v — сокращение от verbose — многословный) и вызывает распечатку строк процедуры по мере их считывания. Это облег- чает поиск синтаксических ошибок. Указанный механизм можно включить и без вмешательства в процедуру с помощью команды вида sh —v proc ... где proc — это имя отлаживаемой процедуры. Нежелательных побочных эффектов можно избежать, если использовать флаг —п, который блокирует выполнение команд процедуры. (Коман- да set —п, введенная с терминала, сделает этот терминал бездей- ствующим до тех пор, пока не будет введен признак конца файла.) Команда set —х включит трассировку выполнения. Команды будут печататься по мере выполнения после подстановки в них значений пере- менных. При помощи флага —и можно выявить случаи использования неинициализированных переменных оболочки. Если такой флаг
86 Гл. 4. Оболочка установлен, любая попытка подстановки переменной, которой не было присвоено значение, приведет к выдаче сообщения об ошиб- ке и прекращению выполнения процедуры. (Попробуйте испы- cd /usr/man N=n з=“1 # подразумевается nroff ($N), том 1 ($з) for i do case $i in [1-9]*) s-$i ;; - t) N-t ;; — n) N-n :: — *) echo unknown flag ;; • ) if test -f man$s/$i.$s then ${N)roff -man man$s/$i.$s Qlse # поиск no всем томам руководства found-no for j in 1 2 3 4 5-6 7 8 do if test -f man$j/$i.$j then. man $j $i ’found-yes fi done case $found in no) echo \'$i; manual page not found\ . esac fi esac done Рис. 4.3 Один из вариантов команды man тать все эти средства за терминалом, чтобы понять их действие.) Все флаги можно отменить командой set — Флаги оболочки, установленные на данный момент, доступны как $—. (В некоторых системах для отмены флагов используется другая форма записи.)
4.2. Дополнительные возможности 87 4.1.10. Команда man На рис. 4.3 приведен один из вариантов команды man, которая печатает разделы из Programmer s Manual (Руководство для программиста). Эта команда вызывается, например, так: man sh man —t ed man 2 fork Первая команда выдаст описание команды sh. Поскольку том руководства не задан, подразумевается первый том. Вторая команда подготовит описание редактора ed для печати на фото- наборном устройстве (опция —t). Последняя команда выдаст страницу руководства с описанием системной функции fork из второго тома. 4.2. ДОПОЛНИТЕЛЬНЫЕ ВОЗМОЖНОСТИ 4.2.1. Передача параметров Переменные языка оболочки могут получать значения либо в ре- зультате явного присваивания, либо при вызове командной процедуры. Если параметр процедуры имеет вид имя = значение и предшествует имени команды, то значение присваивается пере- менной имя перед началом выполнения процедуры. Значение переменной имя в вызывающей оболочке не изменяется. Напри- мер, в результате user=fred команда указанная команда будет выполнена со значением переменной user, равным fred. Если установлен флаг —к, то выражения вида имя=значение интерпретируются таким образом в любом месте списка параметров вызываемой процедуры. Такие переменные иногда называют ключевыми параметрами. Остальные параметры являются позиционными параметрами $1, $2, ... . Команду set можно использовать также для установки пози- ционных параметров внутри самой процедуры. Например, в ре- зультате выполнения команды set — * значением $1 станет имя первого файла в текущем оглавлении, значением $2 — имя следующего файла и т. д. Первый пара- метр — минус — гарантирует правильную обработку в том слу- чае, если имя первого файла начинается со знака минус. Среда процесса — это список пар «имя-значение», который передается в выполняемую программу таким же образом, как
88 Гл. 4. Оболочка и список обычных параметров. Оболочка взаимодействует со средой несколькими способами. Когда оболочка вызывается, она просматривает среду и создает для каждого найденного имени переменную, присваивая ей соответствующее значение. Выпол- няемые команды наследуют ту же среду. Изменение значений этих переменных и создание новых переменных не влияет на сре- ду, если только для внесения параметров в нее не использовалась команда export. Среда выполняемой команды строится из всех неизмененных пар «имя-значение», первоначально унаследован- ных оболочкой, и из всех пар для измененных или новых экспор- тируемых переменных. При вызове командной процедуры можно задавать как по- зиционные, так и ключевые параметры. Ключевые параметры для командной процедуры можно. также задавать неявно, если определить их заранее как экспортируемые. Например, команда export user box помечает переменные user и box как экспортируемые. При вызове командной процедуры делаются копии всех экспортируемых переменных; эти копии и используются в вызываемой процедуре. Изменение значений таких переменных внутри вызываемой про- цедуры не меняет их значений в вызывающей программе-обо- лочке. И вообще командная процедура, как правило, не может изменить состояние вызвавшей ее программы без явного на то запроса. (Исключение из этого правила составляют совместно используемые дескрипторы файлов.) Переменные, значения которых желательно сохранить неиз- менными, можно объявить доступными только для чтения (readon- ly). Эта команда имеет такой же вид, что и команда export: readonly имя-переменной ... Последующие попытки присвоить значения таким переменным отвергаются. 4.2.2. Подстановка переменных Если переменной (параметру) оболочки не присвоено никакого значения, то значением такой переменной будет пустая цепочка. Например, если переменной d не присвоено значение, то команды echo $d и echo ${d} ничего не напечатают. Можно задавать подразумеваемую цепочку литер. Так, команда echo ${d—.}
4.2. Дополнительные возможности 89 напечатает значение переменной d, если оно есть, и литеру . в противном случае. Подразумеваемая цепочка литер интерпрети- руется в соответствии с обычными соглашениями об отмене специальных значений литер, поэтому команда echo ${d—'*'} напечатает просто литеру *, если значение переменной d не уста- новлено. Аналогично команда echo ${d—$1} напечатает значение переменной d, если оно присвоено, и значе- ние $1 (если оно существует) в противном случае. Переменной можно присвоить некоторое подразумеваемое значение: команда echo ${d=.} напечатает ту же цепочку литер, что и команда echo ${d—.} и, если значение переменной d не было установлено, ей будет при- своена цепочка, состоящая из одной точки. Запись вида ${...=...} не допустима для позиционных параметров. Если переменная обязательно должна иметь значение, а под- разумеваемого значения не существует, запись вида echo $ ^сообщение} можно использовать для печати значения переменной d, если оно есть; в противном случае оболочка печатает сообщение, и выполнение командной процедуры прекращается. Если сооб- щение не задано, то выдается некоторое стандартное сообщение. Командная процедура, для выполнения которой требуется уста- новить ряд параметров, может начинаться следующим образом: : ${user?} ${acct?} ${bin?} Двоеточие представляет собой встроенную в оболочку команду, которая не выполняет никаких действий, однако ее параметры вычисляются. Если же хотя бы одна из переменных user, acct или bin не установлена, то выполнение процедуры будет пре- кращено. 4.2.3. Подстановка команд По аналогии с параметрами можно подставлять и стандартный вывод команды. Команда pwd выдает в стандартный вывод имя текущего оглавления. Например, если текущим является оглав- ление /usr/fred/bin, то команда d='pwd'
90 Гл. 4. Оболочка эквивалентна команде d=/usr/fred/bin Вся заключенная между знаками тупого ударения цепочка литер воспринимается как команда, которую следует выполнить, и заменяется результатом выполнения этой команды. Подстав- ляемая команда записывается с использованием обычных согла- шений об отмене специальных значений литер, за исключением того, что перед самим знаком тупого ударения, если он исполь- зуется в команде, следует помещать обратную косую черту. Например, команда Is 'echo эквивалентна команде 1s $1 Подстановка команд выполняется везде, где допускается под- становка параметров (включая встроенные документы), а трак- товка полученного в результате текста одинакова в обоих слу- чаях. Этот механизм позволяет использовать в процедурах коман- ды обработки цепочек литер. Примером такой команды является команда basename, которая удаляет из цепочки заданный суф- фикс. Например, команда basename main.с .с напечатает цепочку main. Ее использование показано на примере следующего фрагмента команды сс: case $А in *.с) B='basename $А .с' esac Здесь переменной В будет присвоена часть значения $А без суф- фикса .с. Вот несколько более сложных примеров: for i in 'Is —t'; do... Переменной i в качестве значений присваиваются имена файлов, упорядоченные по времени последней модифи- кации, начиная с имени файла, модифицированного последним. set 'date'; echo $6 $2 $3, $4 Напечатается, например, сообщение 1970 Feb 3, 11:59:59. Вывод команды date имеет вид Tue Feb 3 11:59:59 GMT 1970. Оболочка разбивает эту строку на слова и пере-
4.2. Дополнительные возможности 91 дает их в качестве параметров команде set, которая при- сваивает их позиционным параметрам. а='ехрг $а + Г Значение переменной а увеличивается на 1. 4.2.4. Вычисление и отмена специальных значений Оболочка представляет собой макропроцессор, который обеспе- чивает подстановку переменных, подстановку команд и порож- дение имен файлов для использования в качестве параметров команд. В этом разделе рассматриваются порядок выполнения этих операций (порядок «вычисления» команды) и действие различных механизмов отмены специальных значений. Перед выполнением команды производятся следующие под- становки: • Подстановка переменных Конструкция $user — пример подстановки переменной. Подстановка выполняется только один раз, оболочка не анализирует подставленную цепочку на предмет даль- нейших подстановок. Например, если значением пере- менной X является цепочка $у, то команда echo $Х выведет $у. • Подстановка команд Конструкция 'pwd'— пример подстановки команды. Например, внутри входного файла переменную НОМЕ можно установить следующим образом: HOME='pwd' Такой входной файл не зависит от имени регистрацион- ного оглавления. • Интерпретация пробелов После выполнения описанных выше подстановок полу- ченная в результате последовательность литер разби- вается на слова, не содержащие пробелы (этот процесс называется интерпретацией пробелов). Пробелами счи- таются литеры, содержащиеся в цепочке $IFS. По умол- чанию, эта цепочка состоит из собственно пробела, табу- ляции и новой строки. Пустая цепочка считается словом, только если она заключена в кавычки. Например, команда echo "
92 Гл. 4. Оболочка передаст программе echo в качестве первого параметра пустую цепочку, в то время как команда echo $null вызовет программу echo без параметров, если значение переменной null не установлено или является пустой цепочкой. • Порождение имен файлов Наконец, каждое слово просматривается с целью обна- ружения литер *, ?, и [ ... ], используемых в образцах, и такое слово заменяется порождаемым списком имен файлов (в алфавитном порядке). Каждое порожденное имя файла представляет собой отдельный параметр. Описанные выше действия выполняются и при вычислении списка слов в цикле for. В слове, по которому осуществляется переключение в конструкции case, выполняется только подста- новка переменных и команд. Наряду с механизмами отмены специальных значений с по- мощью обратной косой черты и одинарных кавычек, описанными в разд. 2.6.3, существует третий механизм — с использованием двойных кавычек. Внутри цепочки литер, заключенной в двойные кавычки, производится подстановка переменных и команд, но порождение имен файлов и интерпретация пробелов не вы- полняются. Приведенные ниже литеры имеют специальное зна- чение внутри двойных кавычек, однако эти значения можно от- менить с помощью литеры \. $ Подстановка переменной. ' Подстановка команды. ” Закрывающая кавычка. \ Отмена специального значения литер $, \ \. Например, команда echo "$х" передаст программе echo значение переменной х в качестве един- ственного параметра. Аналогично команда echo "$*" передаст список позиционных параметров в виде одного пара- метра. Она эквивалентна команде echo "$1 $2 ..." Конструкция $@ эквивалентна $*, за исключением случая, когда она заключена в кавычки. Команда echo
4,2. Дополнительные возможности 93 передаст программе echo последовательность позиционных пара- метров, не вычисляя их. Она эквивалента команде echo "$1" "$2" ... Когда параметры отсутствуют, значением такой конструкции является пустое слово. Это используется в следующем фраг- менте: for I In do cat $i done Гарантируется, что цикл выполнится хотя бы один раз. В этом примере обрабатывается каждый заданный файл. Если не задано ни одного параметра-файла, то копируется стандартный ввод. Металитеры t и ч \ $ * ! 0 нет нет нет нет нет И нет о да да да нет \ нет нет о да нет нет Обозначения: о—ограничитель да—интерпретируется нет—не интерпретируется Рис. 4.4 Отмена специальных значений литер в оболочке На рис. 4.4 для каждого из механизмов отмены специальных значений приводится список интерпретируемых металитер. В тех случаях, когда требуется вычислить цепочку литер более одного раза, можно воспользоваться встроенной командой eval. Например, если переменная X имеет значение $у, а пере- менная у имеет значение pqr, то команда eval echo $Х напечатает pqr. В общем случае команда eval вычисляет свои параметры (как это делают все команды) и передает результат оболочке в качест- ве ввода. Этот ввод считывается и получившаяся команда (коман- ды) выполняете^. Например, если переменная subscript имеет значения user, то команда eval echo \$L_$ubscript
94 Гл. 4. Оболочка эквивалентна команде echo $L_user В этом примере команда eval необходима, поскольку интерпре- тация литеры $ после первой подстановки не производится. Команду eval можно также использовать в случае, когда после подстановки требуется проинтерпретировать синтаксические ли- теры, такие, как |. 4.2.5. Обработка ошибок Обработка ошибок, обнаруженных оболочкой, зависит от вида ошибки и от того, используется ли оболочка в интерактивном режиме или нет. Оболочка считается интерактивной, если ее ввод и вывод связаны с некоторым терминалом (что определяется посредством обращения к системной функции gtty). Оболочка, вызванная с флагом —i, также считается интерактивной. Выполнение команды (см. также разд. 4.2.7) может завер- шиться неудачно по одной из следующих причин: • Переадресацию ввода-вывода выполнить не удалось, на- пример файл не существует или не может быть создан. • Сама команда не существует или не может быть выпол-* йена. Сигнал Описание 1 зависание 2 прерывание х 3 выход 9 уничтожение (не перехватывается и не игнори- 15 руется) программное завершение (от команды kill) Рис. 4.5 Сигналы системы UNIX, используемые в командных процедурах • Выполнение команды завершилось неудачно, например, из-за обращения в чужую память. На рис. 4.5 приво- дится список сигналов, которые представляют интерес для командных процедур. По сигналу выхода, если он не перехвачен, генерируется дамп оперативной памяти. Однако сама оболочка игнорирует сигнал выхода, кото- рый является единственным внешним сигналом, вызы- вающим дамп.
4.2. Дополнительные возможности 95 • Выполнение команды завершилось нормально, но с ко- дом ответа, отличным от нуля. Во всех указанных случаях оболочка перейдет к выполнению следующей команды. Во всех случаях, кроме последнего, обо- лочка выведет сообщение об ошибке. Все прочие ошибки вызы- вают выход из командной процедуры. (Интерактивная же обо- лочка перейдет к чтению следующей команды с терминала.) К таким ошибкам относятся: • Синтаксические ошибки, например if...then...done, где вместо done должно быть fi. • Сигнал, такой, как прерывание. Оболочка ждет оконча- ния выполнения текущей команды (если она есть), а за- тем либо завершает работу, либо вновь обращается к терминалу. Изменить эту подразумеваемую реакцию на прерывания позволяет команда trap. • Ошибка при выполнении любой из встроенных команд, например такой, как cd. Флаг —е вызывает выход из оболочки при обнаружении любой ошибки. 4.2.6. Обработка сигналов Командные процедуры обычно завершаются, если с терминала поступил сигнал прерывания. Команда trap используется в слу- чае, если требуется выполнить какие-либо завершающие дейст- вия, скажем, уничтожить временные файлы. Например, trap 'rm /tmp/ps$$; exit' 2 устанавливает реакцию на сигнал 2 (прерывание с терминала). Если будет получен этот сигнал, выполнятся команды rm /tmp/ps$$; exit Команда exit — это еще одна встроенная команда. Эта команда вызывает завершение выполнения командной процедуры. Коман- да exit в этом примере необходима, поскольку без нее после об- работки прерывания оболочка продолжила бы выполнение про- цедуры с прерванного места. Сигналы могут быть обработаны одним из трех способов. Их можно игнорировать, в таком случае сигнал никогда не пере- дается в соответствующий процесс. Их можно перехватывать, в этом случае процесс должен задать действия, которые следует выполнить при получении сигнала. Наконец, можно вообще не задавать реакции на сигнал, и тогда сигнал вызовет завершение процесса без выполнения каких-либо дальнейших действий. Если к моменту входа в командную процедуру уже задано игнори-
96 Гл. 4. Оболочка рование некоторых сигналов, как это происходит, например, при выполнении фоновой командной процедуры (см. разд. 4.2.7), то команды trap для этих сигналов (как и сами эти сигналы) игнорируются. trap 'rm -f junk$$; exit' 0 1 2 3 15 Рис. 4.6 Пример использования команды trap Использование команды trap иллюстрируется на примере фрагмента командной процедуры на рис. 4.6. Завершающие действия состоят в удалении файла junk$$ и выходе из команд- ной процедуры. Команда trap должна встретиться раньше, чем команда создания временного файла; в противном случае процесс может исчезнуть, но временный файл не будет уничтожен. В самой системе UNIX не используется сигнал 0; в оболочке он означает выход из командной процедуры. Процедура может по своему усмотрению игнорировать неко- торые сигналы. Для этого в качестве параметра команды trap задается пустая цепочка. Следующий фрагмент взят из команды nohup: trap "12 3 15 В результате этого сигналы «зависание», «прерывание», «выход» и «программное завершение» будут игнорироваться как самой про- цедурой, так и запускаемыми ею командами. Реакцию на сигналы можно переустанавливать. Например, команда trap 2 3 восстановит для сигналов 2 и 3 стандартную реакцию. Перечень реакций, установленных на текущий момент, можно получить с помощью команды trap В команде trap совсем не обязательно задавать exit. Про- цедура scan (рис. 4.7) — пример такого использования команды trap: выполнение процедуры возобновляется после обработки сигнала. Процедура scan перебирает все подоглавления в теку- щем оглавлении. Для каждого подоглавления выдается его имя и выполняются команды, вводимые с терминала. Ввод команд заканчивается по признаку конца файла или по прерыванию. Команда : только вычисляет свои параметры, поэтому команда trap : 2
4.2» Дополнительные возможности 47 приводит к фактическому игнорированию прерываний при вы- полнении eval $х. Когда scan ждет ввода, т. е. выполняется read х, действует команда trap exit 2 Встроенная команда read х читает одну строку из файла стан- дартного ввода и помещает результат в переменную х. Она воз- вращает ненулевой код ответа, если был считан признак конца файла или получено прерывание. d=4pwd' for i in ♦ do if fest -d $d/$i then cd $d/$i while echo ”$i‘? trap exit 2 read x do trap : 2; eval $x; done fl done Рис. 4.7 Процедура scan 4.2.7. Выполнение команд Для выполнения большинства команд оболочка прежде всего создает новый процесс, обращаясь к системной функции fork. Новый отдельный процесс требуется для выполнения простых команд, списка команд, заключенного в круглые скобки, таких конструкций, как while и for, при наличии переадресации ввода- вывода. Для встроенных команд новые процессы не создаются. Среда, в которой выполняется команда, включает в себя открытые файлы, значение маски umask, текущее оглавление, реакции на сигналы и устанавливается в порожденном процессе перед началом выполнения команды. Если новый процесс не нужен, используется встроенная команда ехес, которая просто заменяет оболочку новой командой. Например, простейший вариант команды nohup выглядит так: trap "12 3 15 exec "${@?}" Команда trap отключает указанные сигналы, они будут игнори- роваться во всех последующих командах, а ехес заменяет обо- лочку на команду, заданную параметрами. 4 С. Баурн
98 Гл. 4. Оболочка 4.2.8. Переадресация ввода-вывода Большинство способов переадресации ввода-вывода было уже рассмотрено. В приводимых ниже описаниях слово обозначает цепочку литер, в которой выполняются только подстановки переменных и команд. Порождение имен файлов и интерпретация пробелов не производятся. Поэтому, например, команда echo ... >*.с поместит свой вывод в файл с именем *.с. Спецификации ввода- вывода вычисляются слева направо в порядке их записи в коман- де. Если слово является пустой цепочкой, переадресация ввода- вывода не выполняется. Например, команда cat <$1 эквивалентна команде cat без переадресации ввода, если значение параметра $1 не установлено или является пустой цепочкой. > слово Стандартный вывод (дескриптор файла 1) на- правляется в файл слово, который будет создан, если не существует. >> слово Стандартный вывод направляется в файл слово. Если файл существует, то вывод добавляется в конец файла (путем установки указателя записи на конце файла). В противном случае создается новый файл. < слово Стандартный ввод (дескриптор файла 0) берется из файла слово. << слово В качестве стандартного ввода команды берутся последующие строки из файла ввода оболочки до строки, содержащей только это слово (не включая ее). Если перед цепочкой слово стоит литера \, то интерпретация текста во встроен- ном документе не производится. В противном случае выполняется подстановка переменных и команд, а литера \ отменяет специальные значения литер \, $, ' и первой литеры це- почки слово. В этом случае комбинация \новая-строка игнорируется (сравните с цепоч- ками литер, заключенными в кавычки). Если слово является пустой цепочкой, то вводимый текст завершается пустой строкой. >& цифра Дескриптор файла стандартного вывода полу- чается в результате дублирования дескриптора файла цифра при помощи системной функции dup.
4.2. Дополнительные возможности 99 < & цифра Дескриптор файла стандартного ввода полу- чается в результате дублирования дескриптора файла цифра. <&— Стандартный ввод закрывается. >&— Стандартный вывод закрывается. Любой из приведенных выше конструкций может предшество- вать цифра. В этом случае файл будет иметь дескриптор, зада- ваемый этой цифрой, вместо используемых по умолчанию деск- рипторов О или 1. Например, если задана конструкция...2>файл, то при выполнении команды диагностическое сообщение (дескрип- тор файла 2) будет направляться в указанный файл. А конструк- ция ...2>&1 приведет к совмещению файлов стандартного вывода и диагностики при выполнении команды. (Строго говоря, дескрип- тор файла 2 создается посредством дублирования дескриптора файла 1, однако результатом этого является слияние двух по- токов вывода.) Внутри командной процедуры можно переназначить файлы стандартного ввода, вывода и диагностики, используя рассмот- ренные выше конструкции и команду ехес. Например, команда exec >stdout 2>errout переадресует стандартный вывод в файл stdout, а диагностиче- ские сообщения — в файл errout. Эти файлы станут стандартными файлами вывода и диагностики для последующих команд. В среду выполнения фоновой команды, например такой, как list *.с | 1рг & вносятся два изменения. Во-первых, подразумеваемым файлом стандартного ввода для такой команды будет пустой файл /dev/null. Благодаря этому два параллельно выполняющихся процесса (оболочка и фоновая команда) не смогут читать один и тот же файл ввода. В противном случае была бы полная нераз- бериха. Например, команда ed файл & привела бы к тому, что и редактор, и оболочка читали бы одно- временно один и тот же файл ввода. Другим изменением в среде выполнения фоновой команды является отключение сигналов выхода и прерывания. Указанные сигналы будут игнорироваться фоновой командой. Это позволяет использовать их в дальнейшей работе за терминалом, не вызывая при этом прекращения выполнения фоновых команд. Сигнал зависания, вообще говоря, не игнорируется фоновыми процес- сами; для того чтобы он игнорировался, следует воспользоваться командой nohup. Поэтому в системе существует соглашение 4Ф
100 Гл. 4. Оболочка о сигналах, согласно которому, если некоторый сигнал установ- лен в 1 (т. е. игнорируется), его состояние никогда не изменяется, даже на короткое время. Команда оболочки trap не изменяет тостояние игнорируемых сигналов. 4,2.9. Вызов оболочки Приведенные ниже флаги интерпретируются оболочкой при ее вызове. Если первой литерой нулевого параметра1) является знак минус, то считываются и выполняются команды из входного файла .profile. В некоторых версиях системы UNIX также вы- полняется системный входной файл. Вывод программы-оболочки записывается в файл с дескриптором 2. «—с s Если задан флаг —с, то считываются и выполняются команды из цепочки s. Эта опция часто используется программами на языке С для передачи команд оболочке для выполнения. Именно так в редакторе ed реализу- ется команда !. —s Если задан флаг —s или же в команде нет ни одного параметра-файла, команды считываются из файла стандартного ввода. —i Если задан флаг —i или если ввод и вывод оболочки связаны с терминалом (это определяется с помощью системной функции gtty), оболочка является интерак- тивной. В этом случае сигнал завершения игнори- руется (так что команда kill 0 не вызовет прекраще- ния работы интерактивной оболочки), а сигнал пре- рывания перехватывается и игнорируется (поэтому выполнение системной функции ожидания wait может быть прервано). Сигнал выхода всегда игнорируется оболочкой. При обнаружении ошибок, например синтаксических, обо- лочка возвращает ненулевой статус завершения. Если оболочка работала в неинтерактивном режиме, выполнение командного файла прекращается. В противном случае (когда ошибок нет) оболочка возвращает статус завершения последней выполненной команды (см. также команду exit). 4.3. ВСТРОЕННЫЕ КОМАНДЫ Некоторые функции встроены в оболочку либо по необходимости, либо из соображений эффективности. Эти команды выполняются в рамках того же процесса, что и оболочка; переадресация ввода- J) Имеется в виду параметр, значением которого обычно является имя вызываемой команды,— Прим, перев^
4.3. Встроенные команды 101 вывода для них не допускается, за исключением специально оговоренных случаев. : Пустая команда. Эта команда ничего не делает и воз- вращает нулевой код ответа. . файл Считать и выполнить команды из указанного файла, после чего вернуться назад (за команду . файл). Для поиска оглавления, содержащего файл, используется путь поиска $РАТН. break [ п ] Выход из объемлющего цикла for или while, если тако- вой существует. Если задано п, то выполняется выход из п вложенных циклов. continue [nJ Начать следующую итерацию объемлющего цикла for или while. Если задано п, то возобновляется выполне- ние n-го объемлющего цикла. cd [ парам ] Сделать текущим оглавлением парам. Подразумевае- мым значением парам является $НОМЕ. Для поиска оглавления парам используется также переменная оболочки CDPATH, как это подробно описано в разд. 4.1.4. Синонимом команды cd является команда chdir. eval [ парам ... ] Заданные параметры передаются оболочке в качестве ввода, и полученная в результате команда (команды) выполняется. ехес [ парам ... ] Вместо оболочки выполняется команда, задаваемая параметрами ехес. Новый процесс не создается. В команде могут присутствовать спецификации ввода- вывода. Если кроме них в команде ехес нет других параметров, происходит переназначение ввода-вывода оболочки. exit I п ] Выход из оболочки с кодом ответа п. Если параметр п опущен, кодом ответа будет код ответа последней выполненной команды. (Признак конца файла также приведет к выходу из оболочки.) export [ имя-переменной ... ] Указанные переменные помечаются как экспортируе- мые и будут автоматически передаваться в среду вы- полняемых далее команд. Если параметры не заданы, выдается список имен экспортируемых переменных, login [ парам ... ] Эквивалентна команде ехес login парам ... .
102 Гл. 4. Оболочка newgrp [ парам ... ] Эквивалентна команде ехес newgrp парам ... . Команды login и newgrp являются встроенными только в некоторых версиях оболочки. read имя-переменной ... Из стандартного файла ввода считывается одна строка. Слова из этой строки последовательно присваиваются заданным в команде переменным; все оставшиеся слова присваиваются последней переменной. Ненуле- вой код ответа возвращается только при достижении конца файла. readonly [ имя-переменной ... ] Список переменных, доступных только для чтения. Значения указанных переменных в последующих командах присваивания изменить будет невозможно. Если параметры не заданы, выдается список всех переменных, доступных только для чтения. set [ —ekntuvx [ парам ... ] ] —е В неинтерактивном режиме работы прекратить выполнение командного файла при неудачном завершении любой команды. —к Поместить в среду вызываемой команды все ключе- вые параметры, заданные в списке параметров вы- зова, а не только те, которые предшествуют име- ни команды. — п Считывать команды, но не выполнять их. — t Прекратить работу после чтения и выполнения одной команды. — и Считать ошибкой подстановку неустановленных переменных. — v Печатать строки командного файла по мере их считывания. — х Печатать команды и их параметры по мере их вы- полнения. — Отменить опции —х и —v. Форма записи этой оп- ции различна в разных версиях системы. Эти флаги могут задаваться также при вызове обо- лочки. Текущие установки флагов можно найти в $—. Остальные параметры команды set присваиваются по порядку переменным $1, $2, ... . Если не задано ни одного параметра, то будут распечатаны значения всех переменных. shift Позиционные параметры $2 ... переименовываются в $1, ... . times Выдать суммарные времена — время пользователя и
4.3. Встроенные команды 103 системное время,— затраченные на выполнение про-, цессов, запущенных из данной оболочки. trap [ парам И п ] ... Параметр парам представляет собой команду, кото- рую следует считать и выполнить при получении сиг- нала (сигналов) п. Парам вычисляется дважды: сна- чала при установке реакции на сигнал, а потом при его обработке. Одновременно полученные сигналы обрабатываются в порядке их номеров. Если парам отсутствует, то для сигнала (сигналов) п восстанавли- вается исходная (подразумеваемая) реакция. Если парам является пустой цепочкой, то указанный сигнал будет игнорироваться оболочкой и вызываемыми из нее командами. Если п равно 0, команда парам вы- полнится при выходе из оболочки. Если же и отлично от нуля, то парам выполняется по получению сигнала с номером п. Команда trap без параметров выдает список реакций на все сигналы. umask [ ddd ] Маске пользователя, используемой для ограничения полномочий при создании файлов, присваивается восьмеричное значение ddd (см. описание системной функции umask). Если ddd опущено, то выдается те- кущее значение маски. wait I п ] Эта команда ждет окончания работы заданного про- цесса и сообщает его статус завершения. Если п не задано, то wait ждет завершения всех порожденных процессов, активных в данный момент. Кодом ответа этой команды является код ответа ожидавшегося процесса.
ГЛАВА 5 ЯЗЫК ПРОГРАММИРОВАНИЯ С Язык программирования С («Си») использовался для написания операционной системы UNIX и большинства ее команд. Он был разработан в то время, когда писалась операционная система, и совершенствовался в течение 10 лет. На языке С можно писать как машиннозависимые, так и переносимые программы. Первый компилятор с языка был написан для ЭВМ PDP 11/45, теперь же С-компиляторы имеются на многих различных машинах. Исторически на С оказал влияние язык BCPL, разрабатывав- шийся сначала в Массачусетском технологическом институте, а позднее — в Кембриджском университете. Связующим звеном между этими двумя языками был язык В. В языке BCPL отсутствуют типы данных, единственным объ- ектом является машинное слово. Все операции языка определены над словами, и по этому же принципу выполняется распределение памяти. Язык привлекателен своей простотой. Переносимый компилятор с BCPL появился в конце 1960-х годов. Язык ис- пользовался для создания операционных систем. Некоторые особенности языка С легче понять, зная историю его возникновения. Язык предназначался для системного про- граммирования, и важным аспектом считалась его близость к ма- шине. Например, операция ++ имеет прямой эквивалент в на- боре команд ЭВМ PDP 11. В конце 1970-х годов в язык были до- бавлены такие конструкции, как объединения, что позволило писать переносимые программы. Следы происхождения С от языков без типов данных до сих пор видны в том, как свободно в некоторых реализациях можно смешивать целые и текстовые величины, указатели и целые. Проверка типов параметров при вызове функций также отсутствует. В С имеются различные базисные типы данных, такие, как int, char, float и double, а также производные типы данных, ко- торые строятся из базисных при помощи массивов и структур. Другими производными типами являются перечисления, указа- тели, объединения и структуры. Механизм типов в С подобен механизму типов в таких языках, как Алгол 68 и Паскаль. Язык С отличается от них мерой строгости при проверке соот-
5.1. Примеры программ на языке С 105 ветствия типов. Некоторые компиляторы с языка С, например, разрешают присваивание значения указателя переменной целого типа. В Паскале семантика этой операции не определена, и по- этому данная операция не реализована. Вольный подход к типам, принятый в С, позволяет писать такие программы, как, напри- мер, программы распределения памяти, при условии что имеется некоторая информация о реализации системы. В языке С предусмотрены стандартные управляющие конст- рукции: if и switch —для выбора, while и for — для повторения. Кроме того, функции могут возвращать значения, и к ним можно обращаться рекурсивно. Функцию, не возвращающую никакого значения, по аналогии с Алголом 68 можно описать как void. Эта глава представляет собой введение в язык программиро- вания С. В ней также описываются способы организации, со- провождения и отладки С-программ. В следующей главе язык G используется для описания системных функций. В первом разделе данной главы кратко, на примерах, описы- ваются основные элементы языка С. Так как язык развивался в течение многих лет, существуют различные версии компиля- тора. Мы попытались обойти эти различия, однако на вашей машине некоторые средства могут или отсутствовать, или могут быть реализованы другим способом. 5.1. ПРИМЕРЫ ПРОГРАММ НА ЯЗЫКЕ С 5.1.1. Простейшая программа Следующая простейшая С-программа main() { printf("It works.\n"); } выведет на стандартное устройство вывода (терминал) текст It works. Исходный текст программы должен быть помещен в файл, имя которого оканчивается на .с, например simplex. Для ком- пиляции программы нужно вызвать С-компилятор. Для этого служит команда сс simplex которая создает готовую к выполнению программу под именем a.out. Если же задана опция —о, то команда сс —о simple simplex поместит готовую к выполнению программу в файл simple. Для
106 Гл. 5. fl зык программирования С того чтобы выполнить готовую программу, достаточно теперь набрать команду simple. Вернемся к рассматриваемой С-программе. По соглашению, все С-программы должны иметь функцию с именем main, с ко- торой программа начинает выполняться. В данной программе main является единственной функцией. Скобки ( ) означают, что параметры в функции main не используются. Тело функции main заключено в фигурные скобки { и }. Оно состоит из одного оператора, оканчивающегося точкой с запятой, который вызы- вает функцию printf, выполняющую форматный вывод. Текстовые цепочки заключаются в двойные кавычки, как показано в приве- денном выше примере. Комбинация \п внутри цепочек обозна- чает литеру новой строки и при выводе вызывает переход на начало следующей строки. 5.1.2. Восьмеричный дамп Программа на рис. 5.1 представляет собой упрощенный вариант команды od, которая читает свой стандартный ввод и выводит каждую прочитанную литеру в виде восьмеричного целого в файл стандартного вывода. После каждых 10 литер вывод начинается с новой строки. В этой программе демонстрируется несколько новых осо- бенностей языка С. Функции getchar и putchar являются двумя основными подпрограммами ввода-вывода из системной библиоте- ки С. Функция getchar возвращает очередную литеру из стандарт- ного ввода в виде целого числа, a putchar, наоборот, получив це- лое число как параметр, печатает соответствующую ему литеру на стандартном выводе. Первая строка программы — конструкция ^include, кото- рая вставляет в программу определения, необходимые при ис- пользовании стандартной библиотеки программ ввода-вывода. Значение, возвращаемое функцией getchar при достижении конца файла, обозначается символической константой EOF, которая определена в файле заголовков <stdio.h>. Тело функции main состоит из описаний и следующих за ними операторов. Рассмотрим более подробно отдельные конструкции. main( ) Описание функции main, которая является обяза- тельной начальной подпрограммой во всех Сопро- граммах. Int с, п; Описание двух целых переменных сип. п=1; Присваивание переменной п значения 1. (c=getchar( ))! = EOF Выражение c=getchar( ) представляет собой прис- ваивание. Присваивание можно также использовать как часть выражения. Его значением внутри рассмат-
5.1. Примеры программ на языке С 107 риваемого выражения является величина, присваивае- мая переменной с. Операция «!=»—это проверка на неравенство, поэтому ( ... )! = EOF истинно, если #lnclude <stdio.h> int main() { int c, n; n « 1; while ((c « getcharO) I- EOF) { printf("%o ", c); if (n++ >= 10) { n = 1; printf("\n"); }else[ printfC "); } } if (n 1“ 1) { /* завершить неполную строку *f printf("\n"); 1 return(O); } /♦ main */ Рис. 5.1 Упрощенный вариант команды восьмеричного дампа очередная прочитанная литера не является признаком конца файла. while (...){ ... } Вычисляется условие в круглых скобках и, если оно истинно, выполняется заключенное в фигурные скоб- ки тело цикла. Этот процесс повторяется до тех пор, пока условие не станет ложным. Тело цикла — это операторы, заключенные в фигурные скобки. printf("%o", с); Напечатать значение переменной с в восьмеричном формате % о. п++ Увеличить п на 1. Значение этого выражения — зна- чение п до прибавления 1. п++>* = 10; Значение переменной п сравнивается с числом 10 и возвращается результат сравнения — истина
108 Гл. 5. Язык, программирования С или ложь. После выполнения сравнения значение п увеличивается на 1. if (•••) {•••} Вычисляется условие в круглых скобках и, если оно истинно, выполняются заключенные в фигурные скоб- ки операторы. В противном случае выполняется опе- ратор, следующий за else. 5.1.3. Средние расстояния В игре Star Trek знание среднего расстояния до звездной базы из каждого квадранта перед началом игры дает игроку некоторое преимущество. Для решения вопроса о том, разыгрывать ли дан- ную конкретную игру, полезно знать среднее расстояние от лю- бой точки сетки до всех остальных. Приведенная на рис. 5.2 программа печатает средние расстояния для сетки размером 9x9. • Конструкции фinclude и ^define интерпретируются С-препроцессором. Конструкция ^include уже рассма- тривалась в предыдущем примере. Она используется здесь для того, чтобы получить описание функции sqrt( ) из стандартной библиотеки математических фун- кций. Конструкция ^define представляет собой опи- сание константы. Везде, где в программе используется константа ХМАХ, она заменяется на 9. • Описание double average( ); объявляет функцию, возвращающую результат типа double. Это позволяет использовать функцию до ее опре- деления в программе. • Описание double sum = 0.0; объявляет вещественную переменную sum и присваивает ей начальное значение нуль. Все переменные должны быть описаны. Описание переменной должно предшество- вать первому ее использованию. • Оператор for for (х=0; х<ХМАХ; х++) { операторы эквивалентен оператору while
5.1. Примеры программ на языке С 109 #include <math.h> tfdefine ХМАХ 9 #define YMAX 9 double average(); int main() I int x, y; double sum - 0.0; for (x-0; x<XMAX; x++). { printf("°/od: ", x); for (у—0; у < YMAX; y++) ( double s=average(x, y); sum+=s; printf("°/o.2f ”, s); } printf("\n"); } printf("average=°/of\n", sum / (YMAX*XMAX)); j /♦ main */ double average(xO, yO) int xO, yO; { int x, y; double sum = 0.0; for (x-0; x<XMAX; x++) { for (y-0; у<YMAX; y++) { double d = (x-xO)*(x-x0)+(y-y0)*(y~y0); sum += sqrt(d); } } sum /= (XMAX*YMAX-1); return(sum); } /♦ average *! Рис. 5.2 Программа average
по Гл. 5. Язык программирования С х=О; while (х<ХМАХ) { операторы; х++> } Последовательность операторов в фигурных скобках циклически выполняется до тех пор, пока х не станет больше или равен ХМАХ. • Оператор вывода printf("%d: ", х); печатает х в виде десятичного целого и двоеточие с пробе- лом за ним. Первым параметром функции printf является цепочка литер, которая целиком выдается на печать, за исключением содержащихся в ней форматов. Форматы определяют, в каком виде вставляются в печатаемую строку оставшиеся параметры. Например, формат %d заменяется на десятичное представление последующего целого параметра. В приведенной программе исполь- зуются также форматы %f и %.2f. Первый печатает чис- ло с плавающей точкой по подразумеваемому по умолча- нию формату, тогда как во втором случае число с пла- вающей точкой выводится с двумя цифрами после деся- тичной точки. Формат %6.2f определяет поле длиной в 6 позиций, причем две позиции отводятся под дробную часть. • Оператор double s = average(x, у); описывает переменную s и присваивает ей начальное значение, получаемое в результате выполнения функции average с параметрами х и у. • Оператор sum + = s; объявляет операцию присваивания += и эквивалентен оператору sum = sum-f-s; Аналогично в функции average оператор sum /= (XMAX*YMAX— 1); эквивалентен оператору sum = sum/(XMAX*YMAX—1); I В определении функции average описываются тип ее
5.2. Описание языка 111 результата — double и два используемых ею параметра — хО и уО. Оператор return(sum); выполняет возврат из функции с результатом sum. Компиляция программы average выполняется командой сс —о average average, с —1m Параметр —1m требует от сс загрузить библиотеку математиче- ских подпрограмм, содержащую функцию sqrt. 5.2. ОПИСАНИЕ ЯЗЫКА В этом разделе описываются элементы языка программирова- ния С: сначала идентификаторы, константы, базисные типы дан- ных, выражения, затем управляющие операторы, описания функ- ций, массивы и указатели и, наконец, классы памяти. 5.2.1. Лексика Комментарии и пробелы Комментарии начинаются с литер /* и заканчиваются литерами */. Внутри комментария литеры /* не интерпретируются, поэтому вложенные комментарии не допускаются. Для разделения иден- тификаторов и зарезервированных слов используются также пробелы, табуляция и литеры новой строки. Идентификаторы Идентификаторы используются для обозначения переменных, меток и функций. Идентификатор представляет собой последо- auto else int typedef break entry long switch case enum register union char extern return unsigned continue float short void default for sizeof while do goto static double if struct Рис. 5.3 Зарезервированные слова языка С
112 Гл. 5. Язык программирования С вательность литер, состоящую из букв и цифр, начинающуюся с буквы. Литера подчеркивания также считается буквой. Пропис- ные и строчные буквы считаются различными. Длина внешних идентификаторов (используемых более чем в одном программном файле) часто ограничивается 6, 7 или 8 ли- терами, а прописные и строчные буквы в них могут не разли- чаться. Это зависит от конкретной реализации. Ряд идентификаторов зарезервирован под ключевые слова языка; их нельзя использовать в качестве имен переменных. Список зарезервированных ключевых слов приведен на рис. 5.3. В некоторых реализациях зарезервированы также слова asm и fortran. Базисные типы данных В языке С имеется несколько базисных типов данных. Коротко говоря, тип переменной определяет, как будет интерпретиро- ваться значение этой переменной. Значением литерной переменной может быть любая литера из множества допустимых литер. Литера представляется в виде целого числа в коде ASCII или EBCDIC. Имеется три целочисленных типа, которые могут отличаться размером: short int (короткое целое), int (целое) и long int (длин- ное целое). Под более длинные целые отводится память по край- ней мере такого же размера, как под более короткие. Целые без знака описываются как unsigned short int, unsigned int или unsigned long int. Если присутствует unsigned, то int можно опускать. Целые без знака подчиняются законам арифметики по модулю 2Л, где п зависит от реализации. Тип PDP 11/45 VAX 11/780 char 8 8 short int 16 16 int 16 32 long int 32 32 float 32 32 double 64 64 Рис. 5.4 Размеры объектов в С Числа с плавающей точкой обычной точности имеют тип float, а числа с плавающей точкой двойной точности имеют тип double. На рис. 5.4 приведены типичные размеры памяти (в битах),
5.2. Описание языка 113 отводимой под переменные базисных типов данных на ЭВМ PDP 11/45 и VAX 11/780. На обеих машинах литеры представ- ляются в коде ASCII. Константы Целочисленная константа представляет собой последователь- ность цифр. Константа является десятичной, если она не начи- нается с нуля; в противном случае константа считается восьме- ричной. Если последовательности цифр предшествуют литеры Ох или ОХ (0 — цифра нуль), то все последующие цифры считаются шестнадцатеричными, причем буквы a—f или A—F обозначают цифры от 10 до 15 соответственно. Восьмеричная, десятичная или шестнадцатеричная констан- та, значение которой превышает наибольшее для данной машины целое без знака, будет иметь тип long. Для обозначения длинных констант используется буква 1 или L, которая помещается непо- средственно за обычной константой. Например, 0L — это длин- ный нуль. Литерные константы заключаются в одинарные кавычки, например 'с'. Значением литерной константы является код литеры в соответствии с используемой в ЭВМ кодировкой. Ли- тера \ используется для представления ряда специальных литер, как показано ниже: Таблица 5.1 Литера Авторегистр новая строка горизонтальная табуляция возврат на шаг возврат каретки перевод формата обратная косая черта одиночная кавычка пусто - О //////// Любую литеру можно записать как \ddd, где d — восьмеричная цифра. Если за \ следует любая литера, отличная от упомянутых выше, то литера \ игнорируется. Текстовые константы (цепочки) записываются в виде после- довательности литер, заключенной в двойные кавычки: "..Л Внутри текстовой константы действуют те же соглашения о пред- ставлении специальных литер, что и для литерных констант. Цифра, следующая за литерой пусто, должна записываться как
114 Гл. 5. Язык программирования С \000d, где d — эта цифра. Кроме того, \" используется для представления самой литеры двойной кавычки, а комбинация \новая-строка игнорируется, что позволяет записывать длинные текстовые константы в нескольких строках. В конец текстовых констант автоматически вставляется литера пусто \0. Константы с плавающей точкой содержат либо десятичную точку, либо экспоненциальную часть, либо и то и другое вместе. Общая форма записи такой константы имеет вид целая-часть . дробная-часть е ± показатель-степени Все константы с плавающей точкой представляются в памяти как числа с двойной точностью. Ниже приведены примеры констант с плавающей точкой. 0.0 3.14159 ЗеЮ 5.2.2. Выражения и операции Выражения в языке С строятся из констант, идентификаторов, индексированных переменных, ссылок на структуры и объеди- нения и вызовов функций, соединенных знаками унарных и бинарных операций. Бинарные операции, если не оговорено особо, выполняются слева направо. Поэтому выражение а — b — с интерпретируется как ( а — b ) — с Бинарные операции можно разбить на несколько классов. Арифметические операции Бинарными арифметическими операциями являются +, —, * и /, а также операция % получения остатка от деления целых чисел. Если операндами операции деления / являются целые числа, то деление выполняется нацело; десятичная точка и вся дробная часть результата отбрасываются. При делении поло- жительных целых чисел частное округляется в меньшую сторону. Если же один из операндов отрицателен, результат деления зависит от реализации. Операции отношения Операциями отношения являются операции > (больше), >= (больше или равно), <= (меньше или равно) и < (меньше). Эти
5.2. Описание языка 115 операции возвращают значения 1, если условие выполнено, и О в противном случае. Операции сравнения на равенство Для сравнения на равенство используется операция = = , а для сравнения на неравенство — операция ! = . Эти операции воз- вращают 1, если результатом является истина, и 0 в противном случае. Операции сдвига Две операции << и >> позволяют сдвигать битовую шкалу (значение левого операнда) на п позиций влево или вправо соответ- ственно; п должно быть неотрицательным и не должно превышать длину значения в битах. Если сдвигаемая величина имеет знак, то при сдвиге вправо освобождающиеся разряды в зависимости от реализации заполняются или нулями, или единицами. Если же сдвигаемая величина — беззнаковая, то освобождающиеся раз- ряды всегда заполняются нулями. Поразрядные операции Имеются три поразрядные операции: &, I и Л. Операция & пред- ставляет собой поразрядное И, операция I — поразрядное вклю- чающее ИЛИ, а операция Л — поразрядное исключающее ИЛИ. Логические операции Логических операций две: && й ||. Логическая операция && (И) возвращает 1, если значения обоих операндов отличны от нуля, и 0 в противном случае. Операция && отличается от операции & тем, что правый операнд вычисляется только в том случае, если левый операнд не равен нулю. Логическая операция || (ИЛИ) возвращает 1, если значение хотя бы одного из операндов отлично от нуля, и 0 в противном случае. И здесь вычисления выполняются слева направо; второй операнд не вычисляется, если первый отличен от нуля. Операция запятая ВЫр! , ВЫр2 Вычисляются выражения вырх и выр2. Результат вычисления выр! отбрасывается. Результатом операции является 'значение выр2. Эту операцию удобно использовать в случае, когда вы- числение выр! может повлиять на результат вычисления выр2,
116 Гл. 5. Язык программирования С а синтаксис языка требует задания только одного выражения. Например: while ( reserv+ + , word()! = '\n' ) ... В этом примере значение переменной reserv используется функцией word. Операции присваивания Присваивание имеет вид 1-значение == г-значение В качестве 1-значения можно использовать следующие конструк- ции: идентификатор * выражение выражение . поле выражение —> поле выражение [ выражение ] ( 1-значение ) а r-значением может быть любое выражение языка С. Вычисля- ются 1-значение и r-значение, и r-значение присваивается пере- менной, определяемой 1-значением. При присваивании может произойти усечение значения. На- пример, в контексте описаний int i; char с; при присваивании с = i; возможна потеря старших разрядов значения i. Это иногда называется усечением. Верификатор программ lint обнаруживает такие потенциальные ошибки. Операция + = определена таким образом, что х +== у эквивалентно х = х + У- Результатом выполнения операции присваивания является значение, присвоенное переменной в ле- вой части. Операция += является одной операцией присваивания из множества, в которое входят ==, —=, *=, /=, % = , >> = , << = , &=, Л= и | = . Эти операции определяются следующим образом: х ор= у эквивалентно х = х ор у, за исключением того, что выражение х вычисляется только один раз. Условная операция Условная операция ?: имеет вид выр ? выр! : выр2
5.2. Описание языка 117 Если значение выр не равно 0, результатом операции является значение выр!, в противном случае — значение выр2. Если выр! и выр2 имеют различные типы, выполняется преобразование ти- пов, однако арифметические и неарифметические выражения рекомендуется не смешивать. Условное выражение не может быть левой Частью операции присваивания, так как его результат не является 1-значением. Унарные операции Список унарных операций приведен в табл. 5.2. Буква е означает выражение, a v — 1-значение. Таблица 5.2 Операция Описание *е &V —е !е ~е -H-V ' v v-|—j- v (тип)е sizeof(e) sizeof(THn) Значение переменной с адресом е. Используется при работе с указателями. Адрес v. Используется при работе с указателями. Унарный минус. Логическое отрицание. Поразрядное дополнение е. Эквивалентно v = v-(-l. Эквивалентно v=v— 1. Значение v увеличивается на 1. Значением выражения является значение v до увеличения. Значение v уменьшается на 1. Значением выражения яв- ляется значение v до уменьшения. Преобразование значения е к заданному типу. Количество байтов, занимаемых значением е. Количество байтов, занимаемых объектами указанного типа. Преобразование типов значений Явное преобразование значений от одного типа к другому вы- полняется при помощи операции преобразования типа. Преобра- зование типов выполняется автоматически, когда выражение является параметром функции или операндом. Правила преоб- разования типов арифметических значений перечислены ниже. Указатели рассматриваются в разд. 5.2.5. • Значения типов char и short преобразуются к типу int. Литера рассматривается как величина со знаком, и при преобразовании ее в целое происходит распространение знакового разряда. Там, где это уместно, следует исполь-
118 Гл. 5. Язык программирования С зовать короткие целые без знака (unsigned short). Анало- гичным образом значения типа float преобразуются к типу double. • Далее если один из операндов имеет тип double, то и дру- гой преобразуется к типу double. • Иначе если один из операндов имеет тип long, то и дру- гой преобразуется к типу long. • Иначе если один из операндов имеет тип unsigned, то и другой преобразуется к типу unsigned. • Иначе оба операнда имеют тий int. Проверка типов параметров при вызове функций не выполняется. Тем не менее в этом контексте значения типов short или char всегда преобразуются к. типу int, а значения типа float — к типу double. Рекомендуется убедиться в том, что необходимые преоб- разования типов действительно имеют место. Например, выраже- ние sin(3) ошибочно, так как параметр функции sin должен иметь тип double, а не int. Правильное обращение к этой функции имеет вид sin((double)3) или sin(3.0). Приоритеты и порядок выполнения операций На рис. 5.5 приведена сводка всех операций в порядке убывания их приоритетов. Операции, перечисленные в одной строке, имеют одинаковый приоритет. Операции с одинаковым приоритетом Рис. 5.5 Приоритеты операций в С
5.2. Описание языка 119 обычно выполняются слева направо. Однако на рисунке отме- чены исключения из этого правила. Если возникают сомнения или выражение слишком сложное, можно воспользоваться круг- лыми скобками. Порядок вычисления операндов в выражении и параметров в вызове функции в языке С не определен. Поэтому нельзя пола- гаться на то, что побочные эффекты при обращении к функциям имеют место в определенном порядке. Более того, операнды ком- мутативных операций * + & | л могут быть переупорядочены компилятором произвольным об- разом, поэтому выражение а + b + с может вычисляться как (а+Ь)+с или как а+(Ь+с). 5.2.3. Управляющие операторы В языке С имеется ряд управляющих конструкций. Операторы, следующие друг за другом, выполняются последовательно. Для ветвления предоставляются операторы If и switch, а для повто- рения — операторы for, while и do. Условный оператор Условный оператор имеет вид if (выражение) оператор] else оператор2 Вычисляется выражение и, если оно отлично от нуля, выпол- няется оператор!, в противном случае — оператор2. Как опера- тор!, так и оператора могут быть блоками или составными опера- торами вида { необязательные-описания операторы } Часть else можно опускать: if (выражение) оператор! Оператор if (выражение]) if (выражение2) оператор] else оператору
120 Гл. 5. Язык программирования С можно интерпретировать двояко, относя else-часть либо к пер- вому, либо ко второму if. В С else связывается с ближайшим предшествующим if. Рекомендуется избегать такой формы записи и использовать составной оператор, как показано ниже: if (выражение) { Г Оператор switch Оператор switch (переключатель) обеспечивает ветвление по не- скольким направлениям и имеет вид switch (выражение) оператор Вычисляется выражение, значением которого должно быть це- лое. Оператор обычно является составным оператором, в котором некоторые операторы могут быть помечены следующим образом: case константное-выражение: Константное-выражение — это целая или литерная константа (например, 1 или 'А') либо выражение, составленное из таких констант с использованием операций: -----* / о/о + __ << >> & Л I ?: < <= > >= == ! = Оператор, помеченный константным-выражением, выполняет- ся, если целое значение выражения в switch равно значению этого константного-выражения. Если же значение выражения не равно ни одному из константных-выражений, управление передается на оператор default (если он есть). Меткой default: можно поме- чать не более одного оператора переключателя. После выполнения альтернативы будет выполняться следую- щая за ней альтернатива. Для выхода из переключателя исполь- зуется оператор break; Управление будет передано на оператор, следующий за переклю- чателем. Циклы Цикл while имеет вид while (выражение) оператор
5.2. Описание языка 121 Вычисляется выражение и, если его значение отлично от нуля, выполняется оператор. Этот процесс повторяется до тех пор, пока значение выражения не станет равным 0. Оператор в цикле while может быть составным. Оператор for удобен для записи циклов, в которых задаются начальная установка, шаг и условие выхода. Он имеет следую- щий общий вид: for (выражение!*, выражение^; выражение^ оператор Формально этот оператор эквивалентен последовательности выражение!; while (выражение^) { оператор; выражение3; } Операторы for и while проверяют условие завершения в начале цикла. Цикл do...while проверяет условие после выполнения оператора — тела цикла. Таким образом, в цикле do оператор while (выражение); сначала выполняется оператор, а затем проверяется значение выражения. Для выхода из цикла до его окончания используется оператор break. Оператор break; вызывает немедленное прекращение выполнения самого внутрен- него из объемлющих его циклов for, while или do или переклю- чателя switch. Оператор break обеспечивает выход только из од- ного объемлющего цикла. Для выхода сразу из нескольких вло- женных циклов используется оператор goto, например: goto error; Здесь error — метка 'некоторого оператора: error: оператор Метка имеет тот же вид, что и идентификатор. Она должна быть определена в теле той же функции, в которой находится оператор goto. Таким образом, переход из одной функции в другую не до- пускается. Используя подпрограммы setjmp и longjmp, описан- ные в разд. 5.2.9, можно совершать «нелокальные» переходы»
122 Гл. 5. Язык программирования С Другим оператором, который позволяет избежать использо- вания goto, является оператор continue; вызывающий немедленное прекращение выполнения тела цикла и начало следующей итерации. Действие этого оператора эквива- лентно переходу на конец тела цикла, но не за пределы самого цикла. 5.2.4. Функции Функции в языке С аналогичны подпрограммам в Алголе 68 и процедурам в PL/I, Телу программы можно присвоить имя, по которому эту программу можно вызывать отовсюду и столько раз, сколько потребуется. Функцию можно определить, даже если она используется только один раз, просто для того, чтобы вы- делить некоторое действие. Каждая функция должна быть определена. Определение функции включает в себя тип результата, имена и типы формаль- ных параметров и тело функции. Если функция используется в программе до того, как она определена, ее можно описать, ука- зав тип результата и имя функции. В разд. 5.1.3 приведено такое описание для функции average. В противном случае требуется только определение функции. Определение функции имеет следующий общий вид: тип-результата имя-функции (имена-параметров) оп исан ия- п араметро в { тело-функции } Функции, не возвращающей никакого значения, соответствует тип-результата void. Если тип-результата опущен, подразуме- вается int. Кроме того, считается, что функции, которые исполь- зуются в программе до их описания или определения, также воз- вращают целый результат. Тело функции начинается с описаний локальных переменных. Среди последовательности операторов может встретиться опера- тор возврата return. Если нет ни одного оператора return, функ- ция заканчивается после выполнения последнего оператора из ее тела. Оператор возврата вида return; выполняет возврат из функции в точку вызова, не возвращая никакого значения. Если в вызывающую программу значение должно быть возвращено, следует использовать оператор return выражение;
5.2. Описание языка 123 Вызовы функций Вызов функции либо может быть оформлен в виде отдельного оператора, либо может быть частью выражения. Если вызов функции оформлен как отдельный оператор, возвращаемое функ- цией значение теряется. Если функция используется в выраже- нии, она должна возвращать значение. Параметры функций передаются по значению. Каждый пара- метр вычисляется, и копия его значения становится доступной вызываемой функции. Это позволяет внутри тела функции исполь- зовать формальные параметры в качестве локальных перемен- ных, не изменяя значений соответствующих переменных в вызы- вающей программе. В некоторых функциях, например в printf, допускается произвольное число параметров различных типов. Однако printf предполагает, что количество параметров и их типы согласуются с форматом, заданным в качестве первого параметра. Если это не так, то полученные результаты могут быть непредсказуемы. Проверка соответствия типов формальных и фактических параметров не выполняется. Однако такие проверки осуществ- ляет верификатор программ lint. Оператор return позволяет возвратить только одно значение. Результаты можно также возвращать через параметры, исполь- зуя указатели. Если функция не возвращает результата, ее вызов следует оформлять в виде отдельного оператора. Функции могут быть рекурсивными и даже взаимно рекурсивными. Однако определе- ния функций не могут быть вложенными. 5.2.5. Массивы и указатели Массивы Массив — это набор переменных одного типа. Так, описание int а[10]; вводит 10 целочисленных переменных alOl, аШ, ... , а[91. Номер элемента массива задается в квадратных скобках. Переменные с индексами, такие, как аШ или af2*i+4], являются 1-значениями и могут использоваться в выражениях, передаваться в качестве параметров функций. Им можно присваивать значения, напри- мер: a[i]=4; Аналогично описание char с[100];
124 Гл. 5. Язык программирования С вводит 100 литерных переменных с[0], с[1], , с[99]. Можно описывать многомерные массивы, например: int matrix! 10][ 100]; Тем самым создаются элементы матрицы matrix[i][j] для 0^i^9, 0<j<99. Границы массивов являются константами и фиксируются на этапе компиляции. Для определения констант—границ массй- вов обычно используется С-препроцессор. Массивы можно передавать в качестве параметров функций. Однако в отличие от языка Паскаль при описании формальных параметров границы для одномерных массивов можно опускать, например: int length(buffer, size) char buffer!], size; { int i=0; while (i<size && (butfer[i]! = * ') ) { i++; } retum(i); } При вызове функции для самого параметра-массива память не отводится; передаваемым значением является указатель на пер- вый элемент массива. В приведенном примере предполагается, что фактическое количество элементов в массиве buffer передается как отдельный параметр size. Один из способов вызова функции length, гарантирующий правильность обращения, выглядит так: length(array, sizeof(array)) При описании формального параметра-массива может быть опущена только последняя граница; поэтому двумерный массив описывается, например, так: void invert(matrix) int matrix! 10][]; Цепочки литер представляют собой массивы литер. По со- глашению, цепочки в С заканчиваются литерой пусто \0 (об- ратная косая черта, за которой следует нуль). Наличие такой литеры существенно упрощает алгоритм копирования цепочек. Например, функция void copystr (strl, str2) char strl[], str2[]; { int i;
5.2. Описание языка 125 for (i=0; (str2[i]=strl[i]) != '\0'; i++) » } копирует цепочку strl в str2. Тело цикла for в этой функции является пустым оператором. Копирование выполняется при помощи присваивания str2[i] =str 1 [i], которое является побоч- ным результатом вычисления условия выхода из цикла. Указатели Обработку цепочек можно упростить, если использовать указа- тели. Указатель — это переменная, значением которой является адрес другой переменной. Пусть рп — указатель на переменную п, содержащую число 3. Схематически это можно изобразить так, рп п Рис. 5.6 Указатели в языке С как показано на рис. 5.6. Над каждым из прямоугольников ука- зано 1-значение (имя переменной). Внутри прямоугольника по- мещено значение соответствующей переменной. Для описания указателей используется операция косвенной адресации *. Например, указатель рп описывается как int *рп; Обоснованием такого рода описаний является то, что *рп — это значение целого типа, и такое сочетание соответствует исполь- зованию в выражениях операции косвенной адресации *. Унарная операция & позволяет получить адрес переменной. Например, значением выражения &х является адрес перемен- ной х. Оба оператора *рп = п; и рп = &п; имеют смысл. В результате выполнения второго из них рп будет указывать на значение переменной п (первоначально равное 3). Однако присваивание рп == п; ошибочно, так как в рп вместо требуемого адреса целой пере- менной записывается значение 3.
126 Гл. 5. Язык программирования С Между указателями и массивами существует тесная связь. В контексте описаний char *ср; char buffer! 100]; операторы ср = &buffer[O]; и ср = buffer; эквивалентны. Значением указателя ср становится адрес нуле- вого элемента буфера. Аналогично операторы ср = &buffer[4]; и ср = buffer+4; присваивают указателю ср адрес четвертого элемента массива. Указателю на литеры можно присваивать текстовую кон- станту, поскольку значением такой константы является адрес ее первого элемента. Например: char *ср = В общем случае можно складывать указатель р с целым чис- лом i; результатом будет адрес i-ro элемента относительно эле- мента массива, на который указывает указатель р. Так, если ср указывает на bufferfO], то выражение bufferti] эквивалентно вы- ражению *(cp+i). Результат является 1-значением. Вычитание целого из указателя определяется аналогичным образом. Более того, можно вычитать друг из друга два указа- теля на объекты одного и того же типа. Результатом является целое, равное числу элементов между ними. Обычно это указа- тели на элементы одного массива. Для указателей определены операции увеличения и умень- шения. Операция ср++ увеличивает значение ср на размер объекта, на который этот указатель указывает. Значение ср используется в выражении, а затем увеличивается. Аналогично определяются операции ср------, ++ср и-------ср. Примеры Использование указателей иллюстрируют следующие два при- мера. Функция swap определяется так: swap(x, у) int *х, *у; int temp;
5.2. Описание языка 127 temp = *х; *х = *у; *у = temp; } Обращение к ней имеет вид swap(&a, &b); где а и b были ранее определены как int а, Ь; Эта функция меняет местами значения двух целых переменных. Второй пример демонстрирует еще один способ копирования цепочек: void copy(strl, str2) char *strl, *str2; { while (*strH—h = »str2++) J } Эта функция более эффективна по сравнению с ранее рассмотрен- ной функцией копирования цепочек copystr. Проверка на '\0' преднамеренно опущена, так как это условие проверяется по умолчанию. 5.2.6. Структуры и объединения Структуры позволяют объединять вместе группу взаимосвязан- ных данных. Например, характеризуя человека, можно исполь- зовать такие атрибуты, как имя, возраст и вес. Так, конструкция struct { char name [30]; int age; float weight; } someone; определяет, что переменная someone — это структура, состоящая из трех членов (или полей) с именами name (имя), age (возраст) и weight (вес). Для обращения к членам структуры используется операция выделения поля, обозначаемая точкой. Например, операторы someone, age = 21; или copystr("Spike", someone.name); присваивают значения полям age и name соответственно.
128 Гл. 5. Язык программирования С Чтобы не описывать структуру повторно при каждом ее ис- пользовании, для нее можно ввести аббревиатуру. Например, описание struct person { char name[30]; int age; float weight; }; задает для структуры ярлык person, который эквивалентен типу struct{...}, введенному ранее. Используя этот ярлык, можно переписать приведенное выше описание так: struct person someone; Альтернативный способ введения аббревиатуры для типа данных состоит в использовании оператора определения типа typedef. Этот оператор имеет тот же вид, что и описания, за ис- ключением того, что он начинается с ключевого слова typedef. Описанный идентификатор является не переменной, а именем для типа. Например, оператор typedef struct{...} person; вводит имя person для обозначения типа struct{...}. Описание struct { char name[30j; int age; float weight; } someone; теперь можно заменить на person someone; Единственными операциями, которые могут применяться к струк- турам, являются операции , и &. В некоторых версиях языка С разрешается присваивание структур и передача их как парамет- ров при вызове функций. Однако обычно со структурами рабо- тают через указатели. При добавлении к указателю на структуру или вычитании из него целого числа размер структуры учиты- вается автоматически. Пусть ptr — указатель на структуру типа person. Тогда опе- рация ptr —> age
5.2. Описание языка 129 определяется как *(ptr . age ) Результат является 1-значением, соответствующим полю струк- туры типа person. Можно определять структуры, ссылающиеся на себя. На- пример, вершину дерева можно определить так: struct node { struct node «left; struct node «right; int vai; }; В определении структуры node используется сама структура node, однако в структуре содержится не член типа node, а ука- затели left и right на объекты типа node. Указатели на такие структуры широко используются, и для каждой такой ранее определенной структуры удобно определить nodeptr как указа- тель на структуру типа node: typedef struct node «nodeptr; и использовать его наряду с самим определением структуры. Когда требуется узнать размер памяти, занимаемой данной структурой, используется sizeof. Выражение sizeof(o6beKT) или sizeof(THn) возвращает число байтов, занимаемых за- данным объектом или объектом заданного типа. Для создания бинарных деревьев с вершинами типа node требуются средства распределения памяти. В С выделением и освобождением памяти управляет сам программист. В его рас- поряжении имеются две подпрограммы. Подпрограмма malloc(n) выделяет п последовательных байтов памяти и возвращает адрес первого из них, например: struct node «ptr; ptr — malloc(sizeof(struct node)); Поскольку возвращаемый malloc указатель всегда отличен от нуля, значение нуль используется для обозначения того, что ука- затель не указывает ни на какой объект. Такое значение указа- теля определяется, например, следующим образом: ^define nilnode ((nodeptr)O) Память возвращается в свободный пул оператором free(ptr); Указатель ptr должен иметь значение, полученное ранее в ре- зультате обращения к функции malloc. 5 С. Баурн
130 Гл. 5. Язык программирования С В приводимом ниже примере показано использование струк- тур, указателей и подпрограммы распределения памяти malloc. Используются определения, введенные выше для структуры node. Функция new возвращает указатель на вновь созданную вершину дерева, содержащую целочисленное значение, переда- ваемое в качестве параметра: nodeptr new(v) int v; nodeptr n * (nodeptr)malloc(sizeof(struct node)) n->left - n-> right - nilnode; newval «» n->val “ v; return(n); 1 /♦ new Переменной newval присваивается значение вершины, создан- ной последней; эта переменная используется ниже. Другая требуемая функция — это печать дерева. Она опре- деляется следующим образом: void print(n) nodeptr n; { if(n 1- nilnode) { print(n->left); printfC%d\n"1 n->vai); print(n-> right); ) } /♦ print *f. Остальная часть программы приведена на рис. 5.7. Она состоит из функции split, которая вставляет новую вершину в упорядо- ченное дерево с заданным корнем, и функции main, которая вы- полняет все необходимые организационные действия. Особен- ностью работы функции split является то, что недавно вставлен- ные вершины находятся вблизи от корня дерева. Объединения Переменные используются для хранения значений определенного типа. Например, переменной i, описанной как int, нельзя при- своить значение типа float. В программе, требующей значитель- ного объема памяти, часто необходимо уметь использовать одну и ту же переменную для хранения значений различных типов. Для этой цели имеется тип union (объединение).
5.2. Описание языка 131 Например, описание union number { int i; float f; } x; int newval; void split(ladr, radr, tree) nodeptr ♦ladr, *radr; nodeptr tree; if( tree == nilnode ) { ♦ ladr - *radr - nilnode; ) else if(newva1 > tree->val) { ♦ ladr — tree; split(&tree-> right, radr, tree-> right); }else( ♦ radr - tree; split(ladr, &tree->left, tree->left); ) } /♦ split */ main(argc, argv) int argc; char *argv[]; { nodeptr root-new(O); while(argc— > 1) { nodeptr r — new(atoi(argv[1])); split(&r->left, &r->right, root); root - r; argv++; } print(root); } /♦ main ★/ Рис. 5.7 Древовидная сортировка 5*
132 Гл. 5, Язык программирования С отводит под переменную х память, которая достаточна для хра- нения значений как типа int, так и типа float. В каждый момент времени в х может храниться только одно значение. Если х содержит целое значение, то оно доступно как x.i, если же в х находится значение типа float, то оно доступно как x.f. Сам язык не следит за тем, значение какого типа хранится в х в данный момент,— это дело программиста. Для этой цели можно использовать целочисленную переменную или же можно попытаться получить тип х и при помощи какой-либо другой информации, доступной при написании программы. 5.2.7. Препроцессор языка С При компиляции С-программы автоматически вызывается пре- процессор. Строки, начинающиеся литерой *, интерпретируются препроцессором. Программисту предоставляется несколько воз- можностей. Определение констант и макроподстановка Строка вида #define идентификатор лексема... вызывает в оставшейся части программы замену всех вхождений идентификатора на одну или более лексем. Лексема — это иден- тификатор, ключевое слово, константа, цепочка литер, знак операции или знак пунктуации (такой, как ;). Например, опре- деление #define BUFSIZ 512 позволяет использовать в программе идентификатор BUFSIZ, все вхождения которого будут заменяться на 512. Внутри тек- стовых констант замена на определяемые константы не делается. Можно также определять макро, которые могут иметь пара- метры. Макроопределение ^define идентификатор(парп пар2, ... , парп) цепочка-лексем вызывает замену всех последующих вхождений выражения идентификатор(р1,р2,...,рп) на цепочку-лексем, в которой napi заменяется на рп пар2 — на р2, ... , парп — на рп. Список пара- метров может быть пуст, однако макропрепроцессор проверяет, что число передаваемых параметров соответствует числу пара- метров макро. Макроопределения иногда используются вместо определений функций, обычно из соображений эффективности. В отличие от параметра функции параметр макроопределения вычисляется
5.2. Описание языка 133 при каждом вхождении в макроопределение. Поэтому если имеет- ся макроопределение ^define max(a, b) ((a)>(b) ? (a) : (b)) то макровызов max(i++, j++) увеличит i или j на 2. Параметры в этом макроопределении заключены в скобки для того, чтобы избежать возможной двусмысленности. Так как макроопределения обрабатываются препроцессором, то из-за различных приоритетов операций могут возникнуть неожидан- ные результаты. Например, если убрать все скобки в определе- нии, приведенном выше, то расширением max(p?q:r,s) будет выражение p?q:r>s?p?q:r:s которое интерпретируется в С как ( р ? q : ( (r>s) ? (p?q:r) : s ) ) Включение файлов Используя конструкцию Ф include "имя-файла" можно включить в программу содержимое другого файла. Пре- процессор заменяет такую конструкцию на содержимое всего указанного файла. Обычно включаемый файл содержит некото- рый набор определений. Файл ищется сначала в том оглавлении, где находится исходная С-программа, а если его там нет, про- сматривается ряд стандартных системных оглавлений. Конструк- ция Фinclude <имя-файла> также заменяется содержимым указанного файла, однако файл ищется только в стандартных системных оглавлениях; в оглав- лении, содержащем исходную С-программу, поиск не произво- дится. Условная компиляция Условные конструкции позволяют компилировать или не компи- лировать часть программы в зависимости от выполнения неко- торого условия. Обычно это зависит от того, какая ЭВМ исполь- зуется или находится ли программа в стадии отладки.
134 Гл. 5. fl зык программирования С Конструкция для условной компиляции имеет вид #if... часть 1 else часть 2 *endif или #if... часть 1 #endif Условие может принимать одну из следующих форм: * if константное-выражение Проверяется значение константного выражения (разд. 5.2.3) и, если оно равно нулю, компилируется (включается) последую- щий текст. # if def идентификатор Последующий текст компилируется, если идентификатор уже был определен для препроцессора в конструкции ^define. 4j=ifndef идентификатор Последующий текст компилируется, если идентификатор в дан- ный момент не определен для препроцессора. Конструкция =fcundef идентификатор исключает идентификатор из списка определенных идентифика- торов. В некоторых реализациях имеется ряд предопределенных идентификаторов. Их рекомендуется использовать только для определения типа машины, на которой будет выполняться ком- пиляция. Такими идентификаторами являются: geos ibm interdata mert os pdpll tss unix vax 5.2.8. Структура языка Язык С имеет блочную структуру, похожую на блочную струк- туру языка Алгол 60. Однако он отличается от Алгола в одном важном аспекте: описания функций не могут быть вложенными. В С блок представляет собой последовательность описаний и операторов, заключенную в фигурные скобки. Если описания отсутствуют, такая конструкция называется составным операто-
5.2. Описание языка 135 ром. Внутри блоков или составных операторов отдельные опе- раторы сами могут быть блоками или составными операторами. В языке С используются обычные правила для области дейст- вия, характерные для языков с блочной структурой. Описание переменной х во внутреннем блоке отменяет до конца текущего блока действие любого описания переменной х, имеющегося вне данного блока. В этом случае к переменной, описанной вне блока, можно все же обратиться косвенно, например через ука- затель. Спецификации класса памяти определяют требования к па- мяти и область действия переменных. В языке С существуют несколько таких спецификаций: auto, static, extern, register и typedef. Они уточняют описания, например: static int а[20]; или auto char с; Из них typedef называется спецификатором класса памяти только для удобства — он не связан с отведением памяти. Кроме того, описание register аналогично описанию auto. Оно указывает компилятору на то, что из соображений эффективности соответст- вующие переменные следует поместить в регистры. На каждой машине имеется ограниченное число регистров, и их можно ис- пользовать только под переменные определенных типов, напри- мер под целые или указатели. В описании может быть задано не более одного спецификатора класса памяти. Если спецификатор класса памяти отсутствует, то подразумевается auto внутри определения функции и extern вне определений функций. Рассмотрим сначала внешние переменные. Если функция ис- пользует глобальную переменную, эта переменная должна быть внешней (extern). Ее следует определить вне этой функции (возможно, в другом файле). При определении переменной под нее отводится память. Эту переменную можно также описать 'Внутри функции, например: char Iine[80j; main() extern char line []; } Переменные, не являющиеся внешними, будем называть вну- тренними. Каждая переменная, локальная для некоторой функции, на-
136 Гл. 5. Язык программирования С зывается автоматической (динамической) переменной и имеет класс памяти auto. Для таких переменных память обычно отво- дится в стеке. Автоматические переменные создаются при входе в функцию и уничтожаются при выходе из нее. Поскольку время жизни таких переменных ограниченно, следует соблюдать осто- рожность при работе с указателями на них. Наконец, существует класс памяти static. Статические пере- менные могут быть как внешними, так и внутренними. Внутрен- ние статические переменные, т. е. те, которые описаны внутри функций, аналогичны собственным (own) переменным Алгола 60. В отличие от автоматических переменных значения статических внутренних переменных сохраняются от одного вызова функции к другому. Внешние статические переменные описываются вне функций. Областью их действия является вся оставшаяся часть файла, в котором они описаны; они недоступны, однако, ни в каком другом файле. Функцию можно описать как статическую, тем самым ограничив ее область действия файлом, содержащим определение функции. Это используется для ограничения до- ступности функции. В описаниях переменных может быть задана их инициали- зация. • Статические и внешние переменные по умолчанию ини- циализируются нулем. • Все выражения, которые используются для инициализа- ции статических и внешних переменных, должны быть константными выражениями или же выражениями, кото- рые сводятся к адресу ранее определенной переменной плюс или минус некоторое константное выражение. • Автоматические и регистровые переменные могут быть инициализированы произвольными выражениями, ко- рые могут содержать константы, а также ранее опреде- ленные переменные и функции. • Нельзя инициализировать автоматические массивы, струк- туры и объединения. Примеры инициализации переменных: int prime [] = {2, 3, 5, 7}; Так как границы массива не указаны, его размер определяется из размера заданной совокупности констант. Таким образом, создаются переменные prime [0], prime [3]. char messaged = ''You have mail.\n"; Заданная цепочка литер инициализирует массив message и определяет его границы. Заметим, что в конец массива добавляется литера '\0'.
5.2. Описание языка 137 int table [41(3] = { {2, 3, 5 }, { 7, 9, 11 }, { 13, 17, 19 }, { о, О, 0 } }; 5.2.9. Библиотека стандартных программ языка С Стандартная библиотека ввода-вывода Функции из стандартной библиотеки ввода-вывода (stdio) предоставляют пользователям эффективные средства ввода-вы- вода. Для чтения и записи литер используются функции getc и putc, реализованные в виде макроопределений. Обращения к подпрограммам более высокого уровня gets, fgets, scant, fscanf, tread, puts, fputs, printf, fprintf, fwrite можно произвольным об- разом сочетать с выполнением операций более низкого уровня getc и putc. Файл вместе с предоставляемыми средствами буферизации называется потоком. Поток описывается как указатель на пере- менную предопределенного типа FILE. Функция fopen инициа- лизирует поток и возвращает указатель на него. Этот указатель будет идентифицировать поток во всех последующих операциях. Имеется 3 обычно всегда открытых потока с постоянными ука- зателями, которые описаны в файле заголовков и связаны со стандартными файлами ввода-вывода: stdin Стандартный файл ввода. stdout Стандартный файл вывода. stderr Стандартный файл диагностики. Константа NULL означает отсутствие потока. Целочисленные функции, работающие с потоками, возвра- щают целую константу EOF при достижении конца файла или в случае ошибки. Константа EOF определена в файле заголовков <stdio.h>. Этот файл заголовков необходимо включать в любую программу, использующую стандартный пакет ввода-вывода. Из соображений эффективности стандартный пакет ввода-вы- вода по умолчанию буферизует одну строку вывода на терминал и пытается делать это прозрачным образом, выводя накопленную строку всякий раз, когда требуется чтение из. стандартного файла ввода. Прозрачность удается сохранить почти всегда, однако такая буферизация может вызвать неправильное функциониро- вание программ, которые используют стандартную библиотеку ввода-вывода и в то же время сами читают файл стандартного ввода при помощи системной функции read. -
138 Гл. 5. Язык программирования С Функция printf Функция printf уже встречалась в разд. 5.1.2. Она форматирует вывод в соответствии с управляющей цепочкой. Допускаются следующие форматы: % с Литера %d Десятичное целое. %f Число с плавающей точкой. %о Восьмеричное целое. %s Цепочка литер. %х Шестнадцатеричное целое. % % Литера %. Перед буквой, обозначающей любой числовой формат, может стоять буква 1, которая указывает на тип long. Формат также мо- жет включать спецификации размера поля. Знак минус означает, что поле выравнивается по левому краю. Число, следующее за литерой %, определяет минимальный размер поля, отводимого под выводимое значение. Может быть задано и второе число, отделенное от первого точкой; оно определяет максимальную длину поля. Рассмотрим несколько примеров использования форматов: % 2d Напечатать десятичное число, дополнив его при не- обходимости пробелами слева до минимального раз- мера в две литеры. %—3d Напечатать десятичное целое, дополнив его при необходимости пробелами справа до минимального размера поля в три литеры. %. 12s Напечатать цепочку не более чем из 12 литер. % Id Напечатать длинное целое. Модификатор 1 приме- няется ко всем числовым форматам. Функция scanf Функции форматного вывода printf соответствует функция фор- матного ввода scant. В scant формат задается аналогичным об- разом, однако оставшиеся параметры являются адресами пере- менных, куда будут помещены преобразованные значения. Пробелы обычно игнорируются, а любая литера-константа в уп- равляющей строке сопоставляется с соответствующей вводимой литерой. Например, double d; scanf('%ir, &d); читает в переменную d значение константы с плавающей точкой из файла ввода.
5.2. Описание языка 139 Другой пример. Если вводимая строка имеет вид 25 54.32Е—1 thompson то при обращении int i; float х; char name[50]; scanf("%d%f%s", &i, &x, name); переменной i будет присвоено значение 25, x — значение 5.432, a name будет содержать цепочку thompson\0. Если же вводимая строка имеет вид 56789 0123 56а72 то при тех же описаниях в результате обращения scanf("%2d%f%*d%[1234567890]", &i, &х, name); переменной i будет присвоено значение 56, переменной х — значение 789.0, число 0123 игнорируется, а в name будет поме- щено 56\0. Последующий вызов getchar вернет литеру а. Функция scanf возвращает число прочитанных элементов; проигнорированные и неверные элементы данных не учитывают- ся. При достижении конца файла возвращается EOF. Функции для работы с цепочками Пользователю предоставляется полный набор функций для ко- пирования и сравнения цепочек. Эти функции описаны в прило- жении 3. Обработка ошибочных ситуаций В библиотеке стандартных подпрограмм имеются две подпро- граммы — setjmp и longjmp, которые можно использовать для обработки ошибочных ситуаций. Функция setjmp описывается следующим образом: int setjmp(where) jmp__________buf where; При вызове она сохраняет состояние обратившейся к ней про- граммы, чтобы далее можно было использовать функцию longjmp. Возвращаемое значение равно нулю. Для восстановления сохраненного состояния программы ис- пользуется функция longjmp: void longjmp(where, val) jmp_Jbuf where; int val;
140 Гл. 5. Язык программирования С После вызова longjmp выполнение программы возобновляется с точки вызова функции setjmp. Функция setjmp как бы возвра- щает значение val. Описание типа данных jmp__buf содержится в системном файле заголовков. Эти функции используются в интерактивных программах, когда требуется обработать серьезные ошибки, возвратиться в стандартное место в программе и запросить у пользователя дальнейшие инструкции. 5.2.10. Послесловие Приведенные ниже правила соблюдаются в большинстве Сопро- грамм, входящих в состав стандартной распространяемой версии системы UNIX. Одни правила приводятся только потому, что им следуют много людей. Другие — упрощают чтение и написание программ. • Используйте typedef и избегайте сложных описаний. • Используйте *de^ne Для определения символических констант. В частности, не употребляйте в программе в явном виде целые константы для задания размеров бу- феров и других величин, которые могут измениться. Для символических констант используйте имена, состав- ленные из прописных букв. • Избегайте использования макро вместо функции, за исключением случаев, когда важна эффективность. • Всегда описывайте тип результата для функций и исполь- зуйте явный оператор возврата return. При возврате из функции main всегда указывайте возвращаемое значе- ние, поскольку оно является статусом завершения ко- манды. • Проверяйте значения, возвращаемые системными функ- циями, с целью обнаружения ошибочных ситуаций. • Используйте системные файлы заголовков, такие, как <math.h> и <stdio.h> (разд. 5.1). Не делайте предположе- ний относительно значений символических констант (например, EOF) и кодов литер, используемых в данной машине. • Избегайте условных выражений с операндами нечисло- вых типов. • Примите на вооружение структурированный способ оформления программы и используйте фигурные скобки в управляющих операторах. Комментарий после закры- вающей скобки определения функции полезен, если тело функции занимает больше страницы.
5.3. Организация программ и управление программами 141 • Используйте операцию преобразования типов для преоб- разования к соответствующему типу значений, возвра- щаемых подпрограммами распределения памяти. • Храните файлы заголовков, содержащие определения структур, отдельно от главной программы. Не исполь- зуйте несколько копий одних и тех же описаний; ссы- лайтесь на файлы заголовков, используя конструкцию Фinclude. Храните связанные друг с другом функции в одном файле и используйте спецификацию static для функций, локальных для некоторого файла. • Используйте ifdef как можно реже. Чрезмерное его употребление может затруднить чтение программы. • Выполните команду lint и разберитесь в ее выводе. 5.3. ОРГАНИЗАЦИЯ ПРОГРАММ И УПРАВЛЕНИЕ ПРОГРАММАМИ 5.3.1. Компиляция программ Компиляция С-программ выполняется при помощи команды сс. Простые программы, такие, как программы в приведенных выше примерах, хранятся в виде отдельных файлов. Команда сс average, с компилирует программу average.с и помещает готовую программу в выполнимый файл a.out. Команда сс —о average average, с Поместит готовую программу в файл average. Если же файл average.с является частью большой программы, разбитой на два файла average.с и main.с, то компиляция обоих файлов с полу- чением готовой программы выполняется при помощи команды сс —о average main.с average.c Чтобы не выполнять компиляцию обоих файлов main, с и average.c при изменении в одном из них, можно ввести проме- жуточный шаг. Он состоит в сохранении объектных файлов main.o и average.o, полученных в результате выполнения команды сс —с main.с average.c Готовую программу average в таком случае можно получить, выполнив команду сс —о average main.o average.o Программа-оболочка, например, состоит из 35 файлов с об- щей длиной 4800 строк. Из них 24 исходных файла содержат опре-
142 Гл. 5. Язык программирования С деления функций, а остальные являются файлами заголовков, содержащими определения, которые используются в одном или нескольких исходных файлах. Такая организация программ типична для системы UNIX. Разбиение сложной исходной про- граммы на функциональные части позволяет сократить время компиляции после внесения изменения, а также локализовать имена функций в пределах одной функциональной части, исполь- зуя спецификации static. Это может также облегчить чтение и понимание таких программ. 5.3.2. Команда make При разработке большой программы, состоящей из нескольких исходных файлов и файлов заголовков, приходится постоянно следить за файлами, которые требуют перекомпиляции после внесения изменений. Занятие это утомительное и чревато ошиб- ками. Команда make освобождает пользователя от такой рутин- ной работы и служит для документирования взаимосвязей между файлами. Команда make позволяет задавать информацию о зависимо- стях между файлами. При вызове make обновляет целевой файл, если он зависит от файлов, в которые были внесены изменения с момента последней модификации целевого файла, или создает целевой файл, если он не существует. Для каждой зависимости могут быть заданы некоторые действия, например компиляция исходного файла с получением соответствующего объектного файла или печать файла, измененного с момента его последней печати. Описания зависимостей и соответствующих действий хра- нятся в так называемом make-файле, который по умолчанию имеет имя makefile или Makefile. Например, make-файл для про- граммы average, приведенной в начале этой главы, выглядит так: average: main.o average.o сс —о average main.o average.o Этот файл следует читать так: average зависит от main.o и average.o и если какой-либо из файлов .о имеет более позднюю дату моди- фикации по сравнению с файлом average, то надо выполнить команду сс —о average main.o average.o Команда make имеет достаточно информации о файлах, оканчи- вающихся на .с и .о, чтобы самостоятельно перекомпилировать
5.3. Организация программ и управление программами 143 исходный файл .с, если он был модифицирован позднее соответст- вующего объектного файла .о. Если бы main.с и average.с включали некоторый файл заго- ловков, например defs.h, то make-файл пришлось бы уточнить. Информация о добавочной зависимости могла бы выглядеть так: main.о average.o: defs.h Это вызвало бы перекомпиляцию обоих файлов при изменении содержимого defs.h. В общем случае make-файл содержит последовательность записей, определяющих зависимости между файлами. Первая строка записи представляет собой список целевых (зависимых) файлов, разделенных пробелами, за которым следуют двоеточие и список файлов, от которых зависят целевые. Текст, следующий за точкой с запятой, и все последующие строки, начинающиеся с литеры табуляции, являются командами оболочки, которые необходимо выполнить для обновления целевого файла. Разработка программы g использованием make состоит из следующих шагов: • Подумать и отредактировать файлы. • Выполнить команду make. • Проверить и повторить. В команде make без параметров предполагается, что целевым является первый зависимый файл в make-файле. Целевой файл может быть задан явно. Например, команда make main.o гарантировала бы обновление файла main.o. Команда make имеет несколько полезных опций. Чтобы уз- нать, какие действия требуются для обновления файла, но не выполнять их, можно воспользоваться командой make —п Обычно make печатает каждую команду перед ее выполнением. Эту печать можно отменить, задав опцию —s. Иногда случается, что все файлы находятся в обновленном состоянии, а даты их модификации некорректны. Обеспечить корректность дат можно, воспользовавшись командой make —t которая обновляет эти даты при помощи команды touch. В make-файле могут также содержаться комментарии и за- просы на замену цепочек. Комментарий начинается с литеры ф и заканчивается литерой новой строки.
144 Гл. 5. Язык программирования С, Записи в make-файле вида цепочка! = цепочка2 являются макроопределениями; все последующие вхождения $(цепочка1) заменяются на текст цепочка2. Если цепочка! со- стоит из одной литеры, то скобки можно опускать. Команда make содержит список суффиксов, которые опреде- ляют ряд подразумеваемых правил. По умолчанию, этот список имеет вид .SUFFIXES:; .out .о .с .е .г Л .у .1 .s .р Правило для создания файла с суффиксом s2, зависящего от фай- ла с таким же именем, но с суффиксом si, задается в виде записи, в которой роль имени целевого файла играет sls2. В такой записи специальная макропеременная $* обозначает имя целевого файла с отброшенным суффиксом, $@ — полное имя целевого файла, $< — полный список необходимых условий и $? — список фай- лов, требующих обновления. Например, правило для создания оптимизированных объектных файлов .о из исходных файлов с суффиксом .с имеет вид .с.о: ; сс —с —О —о $@ $*.с 5.3.3. Команда lint При создании не очень маленьких программ можно использовать и ряд других полезных средств. Команда lint не раз уже упоми- налась. Она стоит того, чтобы с ней познакомиться поближе. Хотя некоторые из ее сообщений могут оказаться несуществен- ными, на другие следует обратить внимание, так как они указы- вают на потенциальные ошибки в программе. С-компиляторы обычно не проверяют соответствие между определениями функций и их вызовами. Различные другие про- верки — их часто называют проверками типов — также не вы- полняются. Команда lint пытается восполнить этот пробел. Помимо выполнения проверки на соответствие типов lint печа- тает список неиспользуемых переменных и функций, а также распознает ряд случаев использования неинициализированных переменных. Некоторые из конструкций, которые lint считает сомнитель- ными, формально являются правильными. Например, встретив выражение if (11=0) lint выдает сообщение «константа в условном контексте». Более реальный пример сомнительной конструкции — отсутствие ско-
5.3. Организация программ и управление программами 145 бок: if (х&1 ==0) Вероятно предполагалось if ((х&1)==0) 5.3.4. Библиотеки программ Библиотеки программ, используемые при программировании на С, хранятся в виде архивных файлов. Каждый элемент архив- ного файла сам является объектным файлом. Элементы можно добавлять, модифицировать или исключать, используя коман- ду аг. По соглашению, архивные или библиотечные файлы имеют имена, оканчивающиеся суффиксом .а. Например, библиотека, которая автоматически вызывается в команде сс при компиляции С-программы, хранится в файле /lib/libc.a. В распространяемой версии системы UNIX документация по стандартным библиотекам содержится в разд. 2 и 3 «Руковод- ства для программиста». Стандартная библиотека языка С (libc) состоит из функций, описанных в разд. 2 (системные функции), в разд. 3 (без суффикса) и разд. 3S, содержащем пакет стандарт- ного ввода-вывода (stdio). Если в программе используются функ- ции из разд. 3S, в ней должен быть оператор ^include <stdio.h> В разд. ЗМ описаны некоторые математические функции (на- пример, sqrt()). Их можно использовать, если задать ^include <math.h> в исходной программе. Чтобы получить готовую программу, ис- пользующую эту библиотеку математических функций, в коман- де сс следует задать опцию —Im: сс —о average main.o average.o —Im Другие библиотеки вызываются по имени библиотечного (архивного) файла. Для обращения к стандартным библиотекам можно использовать опцию —1... в команде сс. Сопровождение библиотек Библиотека позволяет использовать набор подпрограмм в других программах. Для создания и сопровождения библиотек служит команда аг. По соглашению, библиотеки хранятся в файлах, имена которых оканчиваются суффиксом .а. Библиотеки состоят из объектных файлов, которые содержат всю необходимую ин-
146 Гл. 5. Язык программирования С формацию для перемещения подпрограммы и связывания ее с главной программой. Для получения выполнимых файлов a.out из объектных файлов и библиотек команда сс использует редактор связей (загрузчик) Id. При поиске неопределенных имен библиотечный файл про- сматривается только один раз. Если библиотечная подпрограмма ссылается на другие имена из той же библиотеки, то ее определе- ние должно предшествовать определениям этих имен. Это на- кладывает определенные соглашения на порядок элементов библиотечного файла. Современные версии системы UNIX содержат программу ranlib, которая создает оглавление библиотеки, что позволяет загрузчику Id обращаться к элементам библиотеки в произволь- ном порядке. В UNIX System V эта функция встроена в аг и Id. В более старых версиях системы UNIX для этих целей предназ- начались программы lorder и tsort. По заданному списку объект- ных файлов lorder образует список пар зависимых имен, a tsort осуществляет частичное упорядочение этого списка, приемлемое для Id. Архивную программу аг можно также использовать для объе- динения любого набора файлов. 5.3.5. Измерение производительности Команда time Команда time позволяет определить суммарное время выпол- нения команды. Возьмем для примера программу average из разд. 5.1.3. Команда time average напечатает сначала результаты выполнения команды average, а затем — строку вида 6.0 real 5.4 user 0.1 sys Реальное время (real) — это астрономическое время, в течении которого выполнялась команда. Время пользователя (user) — это время центрального процессора, затраченное на выполнение пользовательской части программы, а системное время (sys) — это время, затраченное на выполнение системных функций. Про- граммы, выполняющие ввод или вывод большого объема, могут израсходовать значительное количество системного времени. Профилирование Имеется возможность получить профиль выполнения Сопро- граммы, содержащий число обращений и время выполнения для каждой функции. Никаких изменений в программе для этого
5.3. Организация программ и управление программами 147 делать не нужно, но при компиляции в команде сс следует задать опцию —р. Во время выполнения программы создается файл mon.out, содержащий профильные данные. Для печати профиля используется команда prof. %time cumsecs#call ms /call name 62.8 3.62 _sqrt 30.4 5.37 frexp 5.2 5.67 81 3.71 -average 0.6 5.71 doprnt 0.3 5.72 flsbuf 0.3 5.74 _close 0.3 5.76 _printf 0.3 5.77 -Write 0.0 5.77 1 0.00 -main Рис. 5.8 Результаты выполнения команды prof average Например, команда average из разд. 5.1.3 была перекомпи- лирована с опцией —р, а затем выполнена. Вывод, полученный в результате выполнения команды prof average приведен на рис. 5.8. В этом примере профилирование выполнялось только для функций, скомпилированных с опцией —р. 5.3.6. Разное Готовые программы, полученные в результате выполнения коман- ды сс, содержат таблицу символов, которую можно использовать при отладке. Когда программа отлажена, эта таблица больше не нужна, и ее можно удалить (сэкономив тем самым файловое пространство) командой strip, например: strip average Размер памяти, занимаемой готовой программой и ее данны- ми, можно получить с помощью команды size, например: size average Результат работы этой команды имеет вид размер-кода + размер-данных + размер-bss = общий-размер
148 Гл. 5. Язык программирования С где размер-bss — это размер неинициализированного сегмента данных. Получить список всех имен, используемых в программе, позволяет команда пт, например: пт average Для каждого символа будет выведено его имя и указано, является ли он символом данных (переменной) или программным символом (меткой или именем функции). 5.4. ОТЛАДКА С-ПРОГРАММ Большинство программ с первого раза не работает. Если вам повезет, вы сообразите, в чем ошибка, исходя из поведения программы. В противном случае вы окажетесь перед выбором: думать, вставлять операторы printf для печати значений ключе- вых переменных во время счета или же использовать отладчик. Если вы выбрали отладчик, то на PDP 11/45 или 11/70 к вашим услугам отладчик adb, а на VAX 11/780 — отладчик sdb (см. приложение 1), который в большей степени ориентирован на язык С. В этом разделе описывается отладчик adb, поскольку он предоставляет более фундаментальные возможности и более широко распространен, хотя действия, выполняемые отладчиком sdb, аналогичны. В программе могут возникнуть следующие ошибочные ситу- ации: • Она может зациклиться. • Программа может завершиться неожиданно из-за нару- шения защиты памяти или другой ошибки, обнаруживае- мой аппаратурой. • Программа выполняется, хотя ведет себя странным образом и функционирует неправильно. • Ей не удалось получить требуемые ресурсы (например, файлы). Для программы, выполнение которой прервано из-за одной из ошибок, приведенных в разд. 6.6.1, может быть образован файл core, содержащий дамп этой программы (программный код и данные). Возбуждение с терминала сигнала выхода путем ввода литеры А \вызывает завершение процесса с образованием дампа, если только в процессе не был задан перехват этого сиг- нала. Отладчик adb предоставляет запросы для просмотра содер- жимого core-файлов, получаемых при прерывании программ, для печати переменных в различных форматах, для внесения из- менений в двоичные файлы и для выполнения программ в интер-
5.4. Отладка С-программ 149 активном режиме с использованием контрольных точек. Его можно применять для исследования содержимого любых файлов, хотя он предназначен для файлов типа a.out и core. 5.4.1. Отладка программы с использованием дампа Для отладки adb вызывается командой adb objfile corefile где objfile — файл, содержащий готовую программу, a corefile — это core-файл. Часто достаточно набрать только adb, поскольку по умолчанию подразумеваются файлы a.out и core соответствен- но. К выходу из отладчика приводит ввод признака конца файла или запроса $q Запрос $с выдает последовательность вложенных вызовов С-подпрограмм в обратном порядке. Запрос $С выдает последовательность вложенных вызовов вместе со значе- ниями всех локальных переменных для каждой функции (в вось- меричном виде). Запрос $е печатает значения всех внешних переменных. Значение конкрет- ной внешней переменной можно также напечатать в десятичном виде запросом имя-переменной/d 5.4.2. Запросы adb Отладчик adb имеет запросы для анализа содержимого как программного файла, так и core-файла. Запрос ? выводит со- держимое программного файла objfile, а запрос / —содержимое файла corefile. Эти запросы имеют общий вид адрес ? формат и адрес / формат Отладчик хранит текущий адрес, который, как и текущая строка в редакторе ed, обозначается точкой. Когда вводится
150 Гл. 5. Язык программирования С адрес, он становится текущим и присваивается точке. Например, запрос 0l26?i присвоит точке восьмеричное значение 0126 и распечатает коман- ду по этому адресу. Запрос .,10/d распечатает 10 десятичных чисел, начиная с текущего адреса. Значением точки становится адрес последнего распечатанного элемента. После выполнения запроса ? или / продвинуть теку- щий адрес вперед и распечатать следующий элемент можно, просто нажав клавишу возврата каретки, а продвинуть текущий адрес назад и распечатать предыдущий элемент — набрав ли- теру Л. Адрес в adb — это выражение, составленное из десятичных, восьмеричных и шестнадцатеричных целых и символов тестируе- мой программы, которые могут быть объединены с помощью операций: Таблица 5.3 Операция Описание + * % & *а @а Сложение. Вычитание. Умножение. Деление нацело. Поразрядная конъюнкция. Поразрядная дизъюнкция. Округление до ближайшего кратного. Поразрядное отрицание. Содержимое по адресу а в соге-файле. Содержимое по адресу а в объектном файле. Унарные операции имеют больший приоритет по сравнению с би- нарными. Все бинарные операции имеют одинаковый приоритет и выполняются слева направо. Вся арифметика в adb выпол- няется над 32-разрядными словами. 5.4.3. Форматы adb Формат описывает представление выводимых данных. Ниже приведены наиболее часто используемые в запросах / и ? спе- цификации форматов (они следуют за именем запроса). Сущест- вуют также спецификации форматов для длинных значений, на-
5.4. Отладка С-программ 151 пример D — для печати длинного целого в десятичном виде и F — для печати чисел с плавающей точкой двойной точности. Последний формат запоминается, поэтому если в запросе формат не задан, то запрашиваемая величина печатается по предыду- щему формату. Таблица 5.4 Формат Описание b с о d f i s u w Один байт в восьмеричном виде. Один байт в литерном виде. Одно слово в восьмеричном виде. Одно слово в десятичном виде. Два слова как число с плавающей точкой. Машинная команда. Цепочка литер, заканчивающаяся литерой \0. Одно слово в виде целого без знака. Записать слово в файл. В общем случае запрос имеет вид адрес, п запрос модификатор Точке присваивается указанный адрес, и запрос выполняется п раз. В приведенной ниже таблице перечислены запросы отладчи- ка adb. Таблица 5.5 Запрос Описание ? Печать содержимого файла a.out. Печать содержимого соге-файла. Печать текущего адреса. Управление контрольными точками. $ ! Смешанный набор запросов. Выход в оболочку. Присваивание значения переменной отладчика. Отладчик перехватывает сигналы, поэтому сигнал выхода не приведет к выходу из adb. Прерывание вызывает прекращение выполнения текущего запроса и переходит к чтению нового запроса. Для выхода из отладчика используется запрос $q ($Q или AD).
152 Гл, 5. Язык программирования С 5.4.4. Установка контрольных точек в adb Программу можно выполнять под управлением отладчика. Команда adb a.out —* подготавливает файл a.out для тестирования. Чтобы начать вы- полнение тестируемой программы, следует ввести запрос :г ... В этом запросе можно задавать параметры вызова, а также пере- адресацию ввода-вывода в упрощенном виде. Управление пере- дается в программу, а отладчик ждет либо завершения выполне- ния программы, либо получения ею сигнала. Если пришел сиг- нал, например прерывание с терминала или нарушение защиты памяти, отладчик вновь получает управление, а выполнение программы приостанавливается. Тестируемую программу можно также остановить при обращении к заданной функции, установив контрольную точку. Контрольные точки устанавливаются за- просом адрес [, n ] : b где адрес — имя С-функции. Запрос $Ь выдает информацию о местонахождении контрольных точек. Наряду с адресом печатается также значение счетчика — п. Останов на контрольной точке произойдет при n-м проходе через нее. Для снятия контрольной точки используется запрос адрес : d Всякий раз, когда управление попадает в отладчик, можно анализировать содержимое памяти, переустанавливать контроль- ные точки, изменять содержимое переменных и возобновлять выполнение программы. Сигналы выхода и прерывания воздействуют на сам отладчик, а не на отлаживаемую программу. При возбуждении такого сиг- нала выполнение отлаживаемой программы приостанавливается и управление возвращается отладчику. Сигнал сохраняется от- ладчиком и может быть передан в отлаживаемую программу за- просом :с ' , -.s ,
5.4. Отладка С-программ 153 Эту возможность можно использовать для тестирования подпро- грамм обработки сигналов. Если вместо этого ввести запрос :с О то сигнал в тестируемую программу передан не будет. Отлаживаемую программу можно выполнять по шагам, ис- пользуя запрос :s При необходимости этот запрос может запустить программу и приостановить ее после выполнения первой команды. 5.4.5. Карта памяти В системе UNIX имеется несколько форматов для выполнимых файлов. Они информируют систему о том, каким образом следует разместить программу в памяти. Отладчик adb интерпретирует эти форматы по-разному и обеспечивает доступ к сегментам с по- мощью набора карт памяти. Карта памяти создается для каждого файла, анализируемого -отладчиком, и используется для преобразования адресов памяти в смещения относительно начала файла. Запрос ? использует карту памяти для файла a.out, а запрос / — карту памяти для файла core. Хорошим правилом при анализе программы является использование ? для печати команд и / — для печати данных. Карты памяти выводятся запросом $т Каждая карта памяти состоит из двух сегментов, определяе- мых базами Ы, Ь2, длинами el, е2 и смещениями fl, f2. По за- данному адресу памяти А адрес в файле вычисляется следующим образом: Ы А el => адрес-в-файле = (А — Ы) + fl Ь2 А е2 => адрес-в-файле = (А — Ь2) 4- f2
ГЛАВА 6 ПРОГРАММИРОВАНИЕ В СИСТЕМЕ UNIX В этой главе содержится описание интерфейса язык С — опера- ционная система UNIX. Рассматриваются вопросы, возникающие при написании программ, непосредственно взаимодействующих с операционной системой UNIX: создание процессов, обработка прерываний, посылка сигналов и использование транспортеров. 6.1. СОГЛАШЕНИЯ О ПАРАМЕТРАХ Большинство команд в системе UNIX реализовано либо в виде командных процедур, либо в виде программ на С. В обоих слу- чаях программе (процедуре) доступны значения параметров команды. Параметры представляют собой цепочки литер. Сущест- вует ряд не строго определенных соглашений о параметрах, которые следует соблюдать при разработке новых команд. Пер- вые параметры вида — буква часто задают опции. Остальные имена обычно считаются именами файлов. Следовательно, не разумно использовать имена файлов, начинающиеся со знака минус,— это может вызвать большую путаницу. В различных командах параметры интерпретируются по-разному. Одни команды более тщательно проверяют правиль- ность задания параметров, чем другие. Если команда не требует параметров, нельзя полагаться на то, что она проверяет их дейст- вительное отсутствие. В большинстве команд параметры задаются в следующем виде: имя-команды [ опции ] [ файлы ] Иногда в состав опций входят два параметра, как, например, в случае опции —о команды сс: сс —о simple simple.с Из данного правила интерпретации параметров как опций имеется ряд исключений. Команда test, описанная в гл. 4, вычисляет
6.1. Соглашения о параметрах 155 выражение, составленное из своих параметров. Другой пример — команда dd, описанная в приложении 1, которая выполняет пре- образование и копирование файла. Обработка параметров в С-программах Программа на языке С начинает выполняться с вызова функции main, описание которой имеет вид int main(argc, argv, arge) int argc; char «argvl ]; char *arge[ ]; Здесь argv представляет собой указатель на вектор параметров команды, a argc содержит количество параметров в векторе argv. Предположим, что соответствующей программе требуются три параметра: pl, р2 и рЗ. Тогда argc равно 4, argvlOl — имя данной команды, argvll]—указатель на pl, argv[2], argv[3] — указатели на р2 и рЗ соответственно, argv[4] равно 0. Каждый из параметров, доступных через указатели argvl 1], argv[2], argv[3], представляет собой цепочку литер и заканчи- вается литерой '\0'. Int main(argc, argv) int argc; char *argv[J; While (—arge>0) ( printf(’’%s°/oc''1 »++argv, (argc>1) ? ’ ' : V*); retum(O); Рис. 6.1 Команда echo Вектор arge содержит информацию о среде. Во многих про- граммах вектор arge не описывается, а для доступа к среде ис- пользуется подпрограмма getenv. Более подробно этот вопрос рассматривается в разд. 6.5.6.
156 Гл. 6. Программирование в системе UNIX Хотя компиляторы С позволяют опускать параметры, если они не используются, рекомендуется описывать их в любом слу- чае. Верификатор С-программ lint обнаруживает неиспользуемые параметры. int unbuff; int main(argc, argv) int argc; char ♦argv[]; ( char c; char *cp; int copied = 0; while (argc > 1) ( switch (*argv[1)) { case /• цепочка argv[1] содержит опции * I ср - argv[1]; while(c — *++cp){ /* обработка каждой буквы*/ switch(c){ / case 'u': unbuff++; break; default: /♦ непредусмотренная букМ */ I } } break; default: /♦ прочие параметры */ copy(argv[1]); copied++; ) argc—; argv++; } if(copied--0){ copy((char»)0); return(O); } Рис. 6.2 Набросок команды cat
6.2. Базисные средства ввода-вывода 157 tfdefine BUFSIZ 512 copy(s) char ♦s; { char bufferfBUFSIZ]; int length; int fd - 0; /♦ подразумевается стандартный ввод*! if (s) { fd “ open(s, 0); ) do( length - read(fd, buffer, BUFSIZ); write(1, buffer, length); } while (length > 0); return(O); 1 Рис. 6.3 Подпрограмма copy В качестве примера обработки параметров на рис. 6.1 приве- дена простая программа, реализующая команду echo. Команда echo выводит в файл стандартного вывода свои параметры, раз- деленные пробелами. Более полный пример обработки параметров команды приве- ден на рис. 6.2, представляющем собой набросок команды cat. Опция —и устанавливает флаг, используемый функцией сору. Если среди параметров не задано имен файлов, то копируется файл стандартного ввода. Предполагается, что функция сору с пустым указателем в качестве параметра копирует файл стан- дартного ввода. Эта функция приведена на рис. 6.3. В теле цикла анализируется каждый параметр из вектора argv. Если первой литерой является знак минус, то параметр считается опцией. В противном случае это имя файла, и этот файл копируется в стандартный вывод. Добавление новых опций не вызывает никаких проблем, так как схема обработки парамет- ров реализована в общем виде. 6.2. БАЗИСНЫЕ СРЕДСТВА ВВОДА-ВЫВОДА Пакет ввода-вывода с буферизацией (stdio), кратко рассмотрен- ный в гл. 5, обычно годится для выполнения простых операций ввода-вывода. В данном разделе описываются средства ввода-
158 Гл. 6. Программирование в системе UNIX вывода нижнего уровня, предоставляемые операционной систе- мой’ UNIX. Операции ввода-вывода выполняются над открытыми фай- лами. Открытые файлы представлены в системе дескрипторами файлов, причем каждый дескриптор имеет свой номер. При вы- полнении любой прикладной программы можно считать, что не- которые файлы уже открыты. Это файлы с дескрипторами О стандартный файл ввода (только чтение), 1 стандартный файл вывода (только запись), 2 стандартный файл диагностики (чтение и запись). Эти файлы открываются процедурой login и могут быть перена- значены программой-оболочкой. После того как в программе был открыт или создан какой-либо файл, следует сохранить его дескриптор для последующего использования в операциях ввода- вывода. Дескрипторы файлов используются как для транспор- теров, так и для файлов. Файл может быть открыт на чтение, на запись или на модифи- кацию, т. е. и на чтение, и на запись одновременно. Для файлов (но не для транспортеров) предусмотрены средства произволь- ного доступа; эти средства обсуждаются в разд. 6.4.2. Обычно ввод-вывод выполняется в последовательном режиме. Если последним был прочитан или записан некоторый байт фай- ла, то очередная операция ввода-вывода неявно относится к сле- дующему за ним байту. Для каждого открытого файла хранится указатель текущей позиции; значением этого указателя является номер байта, который будет прочитан или записан следующим. Если читается или записывается сразу п байтов, указатель текущей позиции продвигается сразу на п байтов. В файле могут храниться не только литеры, но и другие объ- екты. Например, при выполнении фрагмента программы int i; while(...) { write(l, &i, sizeof(i)); } в файл стандартного вывода будет записана последовательность целых чисел. Для чтения данных из файлов следует использовать аналогичную последовательность операторов. Следует также ис- пользовать ЭВМ того же типа, так как способ хранения такой последовательности литер в файле зависит от реализации. Те же ограничения распространяются на любой тип данных, отличный от char. Вывод: если запись ведется байтами, читать надо тоже по байтам; если записываются целые числа, читать надо тоже целыми числами.
6.2. Базисные средства ввода-вывода 159 6.2.1. Системная функция open Системная функция open позволяет создавать файлы или откры- вать существующие файлы на чтение или запись. Ее описание имеет вид int open(name, mode) char *name; int mode; Здесь name — адрес цепочки литер (заканчивающейся лите- рой '\0'), содержащей полное составное имя файла. Второй параметр (mode) определяет режим доступа к файлу: О чтение, 1 запись, 2 чтение и запись. В некоторых системах функция open имеет и третий параметр. Значением, возвращаемым функцией open, является дескриптор файла. Этот дескриптор используется во всех операциях ввода- вывода с этим файлом. Указатель текущей позиции чтения или записи первоначально устанавливается на начало файла. Если файл не может быть открыт, возвращается значение —1. Это может произойти по одной из следующих причин: • Файл не существует. • Оглавление, имя которого входит в составное имя файла, не существует. • Слишком много открытых файлов. • Попытка открыть на чтение (запись) файл, который нельзя читать (в который нельзя писать). Воспользовавшись системной функцией dup, можно узнать, соответствует ли дескриптор файла какому-либо открытому файлу. Функция dup(fd) возвращает новый дескриптор файла (дубликат), если параметром является дескриптор открытого файла. Если параметр не является дескриптором открытого фай- ла или уже было открыто слишком много файлов, возвращается значение —1. Другой способ проверки состояния открытого файла заключается в использовании системной функции fstat (разд. 6.4.3). 6.2.2. Чтение и запись файлов После того как файл был открыт, над ним можно выполнять операции чтения и записи, используя функции read и write. Описание функции read имеет вид
160 Гл. 6. Программирование в системе UNIX int read(fd, buf, n) int fd; char *buf; int n; При обращении к функции read п литер из файла с дескрипто- ром fd будут помещены в область памяти, на которую указывает указатель buf. Возвращаемым функцией read значением является либо • количество прочитанных литер, если не был достигнут конец файла, либо • нуль, если достигнут конец файла. Функция read может вернуть меньшее количество литер, чем было запрошено. Ввод литеры AD с терминала приводит к тому, что частично набранная строка передается программе, обратившейся к сис- темной функции read (см. также разд. 6.4.4). Если не было на- брано ни одной литеры, то функция read возвращает нуль. По соглашению, это означает конец файла. При последующих запросах чтения можно получить новые литеры, однако этим приемом лучше не пользоваться. Описание функции write имеет вид int write(fd, buf, n) int fd; char *buf; int n; Функция write выводит n литер из буфера buf в файл, задаваемый дескриптором файла fd. Из соображений эффективности рекомен- дуется использовать буфера длиной не менее 64 байт; можно, однако, использовать любую длину в пределах размера наличной памяти и размера массива buf. При обнаружении ошибки (на- пример, неправильный дескриптор файла или неправильный адрес буфера) функция write возвращает значение —1. Для повышения надежности целесообразно включать в программу проверки на ошибочные ситуации. Это позволяет реагировать на такие события, как, например, выход за пределы файла. Проиллюстрируем использование функций read и write на примере. Следующая программа копирует свой стандартный файл ввода в свой стандартный файл вывода. Копирование произ- водится по одной литере char с[11; while (read(0, с, 1) = = 1) { write(l, с, 1);
6.3. Дополнительные сведения о файловой системе 161 Идентификатор с описан как массив литер, что позволяет при его употреблении опускать операцию &. В качестве параметра авто- матически используется адрес литеры с[0]. Приведенная выше программа не эффективна, так как она об- ращается к системной функции для чтения или записи каждой литеры. Программа на рис. 6.3 значительно более эффективна, поскольку в ней нет этих издержек. Эта программа представляет собой функцию сору, используемую в команде cat, приведенной на рис. 6.2. При достижении конца файла, когда больше уже нет литер, которые можно было бы прочитать, функция read, как уже было сказано, возвращает 0. Однако чтение может быть не выполнено и по другим причинам, например если произошло прерывание или задан неправильный дескриптор файла. Полный список всех ошибочных ситуаций, которые могут возникнуть при обращении к системным функциям, приведен в разделе err по приложения 2. Чтобы обрабатывать эти ситуации, пользуясь их символическими именами, необходимо включить в программу файл errno.h: ^include <errno.h> Завершает наш вводный обзор системных функций, опери- рующих с дескрипторами файлов, функция close (закрыть файл). Обращение close(fd) приводит к разрыву связи между дескриптором файла fd и свя- занным с ним файлом (или транспортером). Обычно все файлы закрываются автоматически — при завершении процесса, с ко- торым они связаны; но, так как число одновременно открытых файлов для одного процесса ограничено, иногда необходимо вы- полнять эту операцию и в самой программе. Функция close возвращает 0 в случае успешного завершения и _—1, если задан неверный дескриптор файла. 6.3. ДОПОЛНИТЕЛЬНЫЕ СВЕДЕНИЯ О ФАЙЛОВОЙ СИСТЕМЕ 6 .3.1. Полномочия файла С каждым файлом связан набор полномочий, определяющих, кто имеет права доступа к этому файлу и каковы эти права. Пользо- ватель может иметь право на чтение (г), право на запись (w), право на выполнение (х) или некоторую комбинацию этих прав. В соответствии с правами доступа пользователи делятся на три класса: и Владелец (создатель) файла. 6 С. Баурн
162 Гл. 6. Программирование в системе UNIX g Члены группы. о Прочие пользователи. Полномочия для каждого класса пользователей устанавли- ваются владельцем файла. Полную информацию о текущем состоянии конкретного файла (или оглавления) можно получить, используя опцию —1 команды 1s. Например, команда 1s —1 /etc/motd выдаст строку rw—rw—г------1 adm 0 Jul 28 20:03 /etc/motd Цепочка rw—rw—г представляет собой полномочия файла /etc/motd. Три первые литеры, rw—, определяют права доступа для владельца файла, следующие три — права доступа для чле- нов группы владельца (группы рассматриваются ниже), а три последние, г----, — права доступа для всех прочих пользова- телей. В этом примере владелец и члены группы могут читать данный файл и писать в него, а прочие пользователи могут только читать. Следующее поле — это количество ссылок на файл; для вновь созданных файлов оно равно 1. Слово adm представляет собой регистрационное имя владельца файла. Следующее поле содержит количество байтов в файле (размер файла). В данном примере файл имеет нулевую длину. Дата указывает время по- следней записи в файл (время последней модификации). Наконец, последнее поле содержит имя файла. Если файл предназначен для выполнения, т, е. является либо готовой программой, либо командной процедурой, в его полно- мочиях должен быть установлен флаг выполнения. Например, информация о выполнимой программе /bin/sh выдается командой Is —I в виде rwx----х-----х 1 bin 24272 Jan 10 18:03 /bin/sh Это означает, что программа /bin/sh может выполняться пользо- вателями всех трех классов, но читать этот файл и писать в него может только владелец. Выполнимые программы могут также иметь флаги установки идентификации пользователя и установки идентификации груп- пы. Этот вопрос рассматривается в разд. 6.5.4. Права доступа владельца файла определяются только полно- мочиями, относящимися к владельцу; то, что он может быть и членом группы, значения не имеет. В файл с полномочиями —-—г------rwx
6.3. Дополнительные сведения о файловой системе 163 не сможет писать ни пользователь, ни член группы, но прочие пользователи могут с ним делать все что угодно. Полномочия такого рода не нашли широкого применения. €.3.2. Изменение полномочий файла Полномочия файла могут быть изменены его владельцем при помощи команды chmod. В ранних версиях этой команды полно- мочия задавались только в абсолютном восьмеричном виде (как в команде umask, рассматриваемой ниже). Например, в результате выполнения команды chmod 751 run полномочия файла run будут иметь вид rwxr—X----X т. е. владелец будет иметь все права доступа, в то время как члены группы смогут только читать и выполнять, а прочие поль- зователи — только выполнять этот файл. В команде chmod полномочия могут задаваться как в абсо- лютном, так и в относительном виде. Примеры: и—г Отменить право на чтение для владельца файла, g+w Добавить право на запись для членов группы. о=х Установить для прочих пользователей право на выполнение. Чтобы сделать файл run выполнимым для всех пользователей, достаточно выполнить команду chmod +х run Файл run в этом примере можно было бы заменить списком фай- лов — тогда выполнимыми стали бы все эти файлы. Полномочия файла устанавливаются при создании и впослед- ствии могут быть изменены его владельцем. Максимальный на- бор полномочий, устанавливаемых по умолчанию при создании пользователем любого файла, можно задать командой umask (установить маску пользователя). Команда umask О снимает всякие ограничения — создаваемые файлы будут иметь полномочия rwxrwxrwx. Команда umask 22 задает максимальный набор полномочий на доступ rwxr—хг—х (эта маска используется по умолчанию в некоторых системах). Команда chmod игнорирует текущую маску пользователя. 6*
164 Гл. 6. Программирование в системе UNIX Следующая процедура выдает полномочия файла, созданного с учетом текущей маски пользователя: >/tmp/$$ Is —1 /tmp/$$ rm /tmp/$$ Взаимоотношения между людьми во многих коллективах пользователей UNIX основаны на дружбе и сотрудничестве. В этих условиях нормальным явлением может быть предоставле- ние всем пользователям права на чтение всех файлов. Там, где важна секретность, можно ограничить полномочия, создаваемых файлов до rwx-----------, воспользовавшись командой umask 77; тем самым права доступа будут предоставляться только вла- дельцу. Во многих системах обычные пользователи не могут изменить владельца файла или оглавления. Однако в случае файлов это за- труднение можно иногда обойти путем копирования файла, ис- ключения оригинала и переименования копии. Одним из побоч- ных эффектов этой операции является изменение даты создания файла. 6.3.3. Доступ к оглавлениям Для оглавлений полномочия на чтение, запись и выполнение трактуются несколько иначе, чем для файлов. г Разрешает читать оглавление так, как будто это обыч- ный файл. Оглавление читается, например, програм- мой-оболочкой в процессе порождения имен файлов. х Разрешает доступ к элементам (файлам и подоглавле- ниям) данного оглавления. w Разрешает создавать и исключать элементы оглавле- ния. (В системе UNIX нет отдельных полномочий для этих двух операций.) Чтобы распечатать полномочия для некоторого оглавления, в команде 1s следует задать опцию — d, так как иначе 1s выдаст сведения об элементах оглавления, а не о самом оглавлении. Например, сведения о текущем оглавлении выдаются командой Is — Id . Вывод этой команды имеет вид drwxrwxr—х 5 srb 496 May 5 18:06 . где начальная литера d означает, что этот элемент является ог- лавлением. В некоторых версиях системы команда 1s печатает также имя группы файла (оглавления).
6.3. Дополнительные сведения о файловой системе 165 Ограничения на права доступа к файлам и оглавлениям рас- пространяются на всех обычных пользователей. Единственный пользователь, называемый суперпользователем, освобожден от проверок права доступа. Некоторые операции, например созда- ние оглавлений, могут выполняться только суперпользователем. Это позволяет реализовывать эти операции в виде команд, а не как части операционной системы. Также только суперпользова- телю разрешается изменять владельца или группу файла. Обычно суперпользователь имеет регистрационное имя root. 6.3.4. Группы Как и индентификация владельца, идентификация группы уста- навливается при создании файла. При входе в систему вам на- значается некоторая группа. В некоторых системах всем пользо- вателям назначается по умолчанию одна и та же группа. Иденти- фикацию группы файла можно вывести при помощи опции —g команды 1s. Например, команда Is —1g /etc/motd выводит строку вида rw—rw—г------1 adm 0 Маг 30 20:03 /etc/motd Здесь adm — имя группы. Во время сеанса вы можете изменить свою группу командой newgrp имя-группы при условии что вы — член группы имя-группы. В некоторых системах команда newgrp выводит слово sorry («извините») и при- нудительно осуществляет выход из системы, если вы не являе- тесь членом группы. (Этот недостаток является следствием вы- бранного способа реализации данной команды.) Новые группы создаются администратором системы. Группа может использоваться для объединения пользователей, работаю- щих над общим проектом, для того, чтобы ограничить круг лю- дей, имеющих право доступа к файлам. Этот механизм является громоздким и не пригоден для гибкого использования. С каждым файлом связан как идентификатор владельца^ так и идентификатор группы. Эти идентификаторы представле- ны внутри файловой системы целыми числами и преобразуются в имена (такие, как srb и root) программами типа 1s. Имена поль- зователей и групп наряду с некоторой дополнительной инфор- мацией хранятся в двух файлах — /etc/passwd и /etc/group. Файл паролей /etc/passwd содержит строки вида srb:yKohajlbawhyg:142:3:mh5967,m044:/usr/srb:
166 Гл. 6. Программирование в системе UNIX Двоеточие является разделителем полей. Первое поле — регист- рационное имя пользователя, второе — пароль в зашифрованном виде, третье и четвертое поля — идентификаторы пользователя и группы (в виде целых чисел). Следующее поле содержит инфор- мацию, которая в прошлом использовалась для удаленного ввода заданий. Оно включает регистрационное имя и учетный номер пользователя в местном вычислительном центре. Шестое поле содержит имя оглавления, которое становится текущим при входе в систему. Это то самое регистрационное оглавление, о котором говорилось выше. Последнее поле обычно пусто и используется в случае, когда пользователь запрашивает командный интерпре- татор, отличный от /bin/sh. Файл групп /etc/group имеет сходный формат и состоит из строк вида a68::3:srb,a68 Как и в файле паролей, двоеточие служит разделителем полей. Первое поле представляет собой имя группы, следующее поле — пароль, используемый командой newgrp, третье поле — идентификатор группы. Последнее поле содержит список регист- рационных имен пользователей — членов группы. Имена раз- деляются запятыми. Команда newgrp подобна команде login: она изменяет идентификатор группы процесса. 6.4. ДОПОЛНИТЕЛЬНЫЕ ВОЗМОЖНОСТИ ВВОДА-ВЫВОДА 6.4.1. Создание и уничтожение файлов Для создания файлов в программах можно использовать систем- ную функцию creat, описание которой имеет вид int creat(name, pmode) char *name; int pmode; где name — имя файла, a pmode — его полномочия. Обращение к функции creat приводит к тому, что либо создается новый файл, либо подготавливается к перезаписи уже существующий файл (он усекается до нулевой длины). В обоих случаях файл открывается на запись. Напомним, что в файловой системе для защиты используются 9 бит, определяющих полномочия на чтение, запись и выполне- ние для владельца, членов группы и всех прочих пользователей. Права доступа обычно задаются в виде трех восьмеричных цифр. Права доступа, заданные параметром pmode функции creat,
6.4. Дополнительные возможности ввода-вывода 167 модифицируются согласно маске доступа (umask) процесса, соз- дающего файл. Фактически используется выражение ( ~umask ) & pmode Функция creat возвращает дескриптор файла при успешном завершении и —1 в противном случае. Уничтожить файл можно при помощи системной функции unlink, описываемой в виде int unlink(name) char *name; где name — имя файла. Эта функция обычно возвращает нуль, но —1 обозначает, что соответствующий файл не существует или не может быть уничтожен. Системная функция creat не создает оглавлений. Вместо этого для создания оглавлений используется команда mkdir. Анало- гично, исключать оглавления можно только командой rmdir. С физическим файлом может быть связано более одного имени. Первое имя файл получает при создании. Последующие имена (ссылки) образуются при помощи системной функции link (соз- дать ссылку): int link(namen name2) char *namex, *name2; где name2 — альтернативное имя для файла с именем namef. Функция не выполняется, если файл с именем name2 уже сущест- вует. Прямым аналогом этой системной функции является коман- да In: In файл новое-имя в результате выполнения которой старый файл получает новое имя. Создание файла-замка В завершение данного раздела мы рассмотрим еще несколько примеров. Файл-замок является монопольной собственностью своего владельца. Его можно использовать для обеспечения моно- польного доступа к некоторому ресурсу. Файл-замок создается, например, программой, управляющей построчным печатающим устройством, в начальной фазе ее работы. Если случайно начнет выполняться другой экземпляр той же самой программы, он об- наружит файл-замок и прекратит выполнение.
168 Гл. 6. Программирование в системе UNIX Один из способов создания такого файла показан на рис. 6.4. Используемый метод состоит в создании и открытии файла сле- дующим образом: creat("lock", 0); Второй параметр (0) — полномочия создаваемого файла --------------. Создание файла без права доступа на чтение гарантирует, что другая попытка открыть этот файл на чтение обречена на неудачу. Успешное завершение функции creat означает запирание замка. В противном случае файл уже открыт другим процессом. /* * использование: mklock файл»,» */ int ma1n(argc, argv) int argc; char *argv[J; { int rc * 0; char *n; int f; while (argc—• > 1) ( if ((f - creat(*++argv, 0)) < 0) { rc++; }else{ close(f); ) } return(rc); } Рис. 6.4 Команда mklock Данная программа некорректна, если пользователем является суперпользователь, так как отсутствие полномочий на чтение не является для него преградой. Можно применить и другой метод, заключающийся в создании для уже существующего файла альтернативного имени-замка.
6.4. Дополнительные возможности ввода-вывода 169 #define BUFSIZ 512 #define MODE 0644 /♦ rw - для владельца t Г—— для членов группы ♦/ „ /* и прочих »/ int errflg; void error(s) char s(]; ( . write(2, s, strlen(s)); errflg++; } int main(argc, argv) int argc; char »argv[],’ int rd, wt, n; char b[BUFSIZ]; if (argc!—3) ( /* неверное число параметров •/ errorf'usage; ср fromfile tofile\n"); return(l); } if ((rd-open(argv(1], 0)) -- -1) errorC'cp: cannot open input\n"); if ((wt-creat(argv[2), MODE))----------1) errorC'cp: cannot create output\n"); if (errflg--O) { while (<n-read(rd, b, BUFSIZ)) > 0) { if (write(wt, b, n)!-n) { errorC'cp: write error\n”); break; } } 1 return(errflg); } Рис. 6.5 Упрощенный вариант команды ср
170 Гл. 6. Программирование в системе UNIX Команда ср На рис. 6.5 приведена реализация упрощенной версии коман- ды ср. Прежде всего программа проверяет, что задано правиль- ное количество параметров. Если это условие не выполнено, осуществляется возврат из функции main и, следовательно, вы- ход из программы. Если количество параметров правильное, открываются файлы ввода и вывода и, если это удалось сделать, в цикле while выполняется копирование. В программу включена также проверка на ошибочные ситуации при записи — этот во- прос обсуждается далее в разд. 6.6.3. Функция strlen, входящая в системную библиотеку стандартных С-программ, возвращает длину цепочки, переданной ей в качестве параметра. Создание временного файла В командных процедурах часто создаются временные файлы, используемые только во время выполнения данной процедуры. Имеется два оглавления, /tmp и /usr/tmp, в которых любые пользователи могут создавать временные файлы. Файлы, создан- ные в этих оглавлениях, должны быть уничтожены программой, создавшей их. При перезагрузке системы эти оглавления обычно очищаются. Одно из часто используемых в командных процедурах согла- шений заключается в создании файлов с именем /tmp/$$ Этот метод надежен при условии, что ему следуют все пользо- ватели. Команда mktemp, приведенная на рис. 6.6, использует для порождения новых файлов функцию mktemp из библиотеки стан- дартных С-программ. Типичное обращение к команде mktemp имеет вид mktemp /tmp/XXXXXX В результате печатается имя созданного файла, например: /tmp/022780 Это имя можно затем использовать в командных процедурах. Например, в результате выполнения tmp='mktemp /tmp/XXXXXX' переменной языка-оболочки tmp будет присвоено имя временного файла, созданного командой mktemp.
6.4. Дополнительные возможности ввода-вывода И #include <stdio.h> /* * mktemp — создать временный файл */ char ♦mktempO; int main(argc, argv) int argc; char ♦argvfj; ( int rc “ 0; char *n; int f; while(argc— > 1) { n - mktemp(*++argv); if((f - creat(n, 0644)) < 0) {. fprintf(stderr, "mktemp: cannot create '%s’\nl’( rc++; } else ( , fprintf(stdout, "%s\n",-n); close(f); } • return(rc); } Рис. 6.6 Создание временного файла 6.4.2. Ввод-вывод — метод произвольного доступа Файл состоит из последовательности литер, и чаще всего ис- пользуется метод последовательного доступа. Однако файл мож- но читать или записывать и не последовательно путем установки указателя текущей позиции внутри файла при помощи системной функции Iseek. Определение функции Iseek имеет вид long Iseek(fd, offset, whence) int fd; long offset; int whence;
172 Гл. 6. Программирование в системе UNIX Функция Iseek устанавливает указатель текущей позиции файла с дескриптором fd на позицию offset (смещение). Смещение бе- рется относительно позиции, определяемом параметром whence (откуда). Последующее чтение или запись начнется с этой пози- ции. Параметр смещение (offset) является длинным целым, fd и whence — оба целые, причем whence может принимать значения О, 1 или 2. Эти три значения имеют следующий смысл: О Смещение относительно начала файла. 1 Текущая позиция + смещение. 2 Конец файла + смещение. Примеры: lseek(fd, 0L, 2) Указатель текущей позиции устанавливается на конец файла. lseek(fd, 0L, 0) Установка на начало файла без потери данных. (В ран- них версиях системы UNIX вместо функции Iseek ис- пользовалась функция seek; различие между ними за- ключается в том, что в функции seek параметр-смещение является обычным, а не длинным целым.) В ошибочных ситуациях, которыми являются, например, • неопределенный дескриптор файла, • попытка установки указателя текущей позиции для тран- спортера, • попытка выйти за начало файла, функция Iseek возвращает значение —1. Используя Iseek, можно создавать файлы с «дырами». Если записать файл до некоторого места, а затем установить указа- тель текущей позиции за конец файла, то образуется участок файла, не содержащий данных. Этот прием полезен в некоторых приложениях, например при сортировке большого объема дан- ных с использованием хеширования. В действительности же эти дыры не занимают физического пространства в файловой сис- теме. 6.4.3. Состояние файлов Состояние файлов можно определить при помощи системных функций stat и fstat. Обращаясь к функции stat, можно получить информацию о любом поименованном файле. Параметром функ- ции fstat является дескриптор файла; эта функция возвращает
6.4. Дополнительные возможности ввода-вывода 173 информацию об открытых файлах и транспортерах. В остальном эти функции являются полностью аналогичными, поэтому ниже описывается только функция stat. Описание этих двух функций имеет вид int stat(name, but) char «name; struct stat *buf; struct stat { devj st_dev; inoj stjno; unsigned short stjnode; short stjilink; short st_uid; short st_gid; devj stjdev; off jt st_size; timej st_atime; timej stjntime; time t st ctime; ); ' ' #define SJFMT 0170000 /♦ маска для выделения типа файла ♦ / #define- SJFDIR 0040000 /♦ оглавление ♦/ #define SJFCHR 0020000 /♦ специальный литерный *1 # define SJFBLK 0060000 /♦ специальный блочный */ #define SJFREG 0100000 /♦ обычный файл ♦/ #define SJFMPC 0030000 / ♦ му ль типлексируемый спец литерный * / tfdefine SJFMPB 0070000 /♦ мультиплексируемый спец блочный • / #define S1SUID 0004000 /♦ установить идентификатор пользователя*! /* при выполнении */ #define SISGID 0002000 /♦ установить идентификатор группы при выполнении */ #define SJSVTX 0001000 /♦ сохранить программный сегмент *1 Sdefine SJREAD 0000400 / ♦ право на чтение для владельца */ ^define SJWRITE 0000200 / ♦ право на запись для владельца ♦ / ttcfofine S IEXEC 0000100 / ♦ право на выполнение/поиск для владельца ♦ / Рис. 6.7 Системный файл заголовков (sys/stat.h)
174 Гл. 6. Программирование в системе UNIX /* » Вычисление контрольной суммы для списка файлов *1 V. #includfe <sys/types.h> ^include <sys/stat.h> char *ctime(); struct stat STATBUF[1]; int fd; char buf[512); int main(argc, argv). int argc; char ♦argv[J; { int i; for(i - 1; i < argc; i++) { close(fd); if ((fd - open(argvl'i), 0)) < 0) printf("°/os: cannot open\n",’ argv[i]); else{ fstat(fd, STATBUF); chksum(argv[i]); } 1 return(O); } /* main */ chksum(nam) char ♦nam; { register int p, e; register unsigned short sum '» 0; char *c; while(e - readbO) ( for(p = 0; p < e; p++) { if(sum&01) ( sum = (sum»1) I 0x8000;
6.4. Дополнительные возможности ввода-вывода 175 .} else{ sum »“ 1; sum л= buf[p]; } } с = ctime(&STATBUF->st_mtime); if((STATBUF->st_mode&S_IFMT) — SJFREG) { printf("%-14s °/oo\t0/os", nam, sum, c); } } /♦ chksum *1 int readb() register int r; r = read(fd, but, sizeof(buf)); return((r <« 0) ? 0 : r); )• /♦ readb *! Рис. 6.8 Команда chksum int fstat(fd, buf) int fd; struct stat *buf; Структура stat описана в системном файле заголовков <sys/stat.h>. В этом файле определены также константы, которые можно использовать для обращения к полям структуры stat. Содержимое этого системного файла заголовков приведено на рис. 6.7. Поля имеют следующий смысл: st__mode Тип файла. Это поле определяет, является ли дан- ный файл обычным файлом (например, файлом поль- зователя), оглавлением, специальным блочным (без буферизации) или специальным литерным (с буфе- ризацией) файлом. st__uid Идентификатор владельца. st__gid Идентификатор группы владельца. st__size (Относительный) номер байта, записанного послед- ним. st__atime Время последнего чтения из файла (последнего до-
176 Гл. 6. Программирование в системе UNIX ступа к файлу). Это поле не устанавливается при просмотре оглавлений. st__mtime Время последней записи в файл (или время созда- ния файла). На это поле не влияют изменения вла- дельца, группы или полномочий. st__ctime Это время устанавливается при записи в файл или при изменении владельца, группы или полномочий. Все эти поля выводятся командой 1s при задании соответствую- щих опций. Использование информации о состоянии файлов иллюстрируется на рис. 6.8 на примере программы chksum. Программа chksum для каждого параметра выводит строку вида chksum.с 170242 Thu Dec 16 03:32:55 1982 Константа S_____IF REG определена в системном файле заголов- ков <sys/stat.h> и обозначает значение (st_mode&S__IFMT) для обычного файла. На поле st__mode приходится накладывать ма- ску S_______________________IFMT потому, что оно содержит также и биты, опреде- ляющие полномочия. 6.4.4. Организация ввода-вывода для терминалов Для каждого процесса файл /dev/tty представляет собой управ- ляющий терминал, связанный с данным процессом. Этот файл можно использовать в программах, когда требуется выдать со- общение на терминал, даже если файлы стандартного вывода и диагностики переназначены. Его можно также использовать для ввода с терминала или вывода на терминал в случае, если вызываемая команда требует задания имени файла.. Самый первый файл-терминал, открытый процессом, становит- ся управляющим терминалом данного процесса. Обычно терми- нал открывается в процедуре входа в систему (login), и все порож- даемые процессы наследуют этот же управляющий терминал. С управляющего терминала можно возбуждать сигналы выхода и прерывания — этот вопрос обсуждается ниже. Множество процессов, связанных с одним и тем же управляющим термина- лом, называется группой процессов. Любой терминал, связанный с одним из этих файлов, работает в дуплексном режиме. Литеры, набранные на клавиатуре тер- минала, поступают в ЭВМ, где они передаются программе, а так- же отображаются системой обратно на терминал. Литеры можно вводить в любое время, даже когда идет вывод. Имеется ограни- чение на максимальное количество литер, которое можно ввести до того, как их прочитает процесс. Это ограничение определяется размером системных буферов (обычно 256). При выходе за эту границу вводимые литеры просто теряются.
6А. Дополнительные возможности ввода-вывода 177 Ввод с терминала собирается в строку, так что при обраще- нии к функции read выполнение задерживается до тех пор, пока не будет набрана целая строка. Функция read возвращает только одну строку, даже если запрошено большее количество литер. Если запрошено меньшее количество литер, функция read возвращает именно это количество литер. Никакой потери информации при этом не происходит. Путем обращения к систем- ной функции ioctl с соответствующей опцией программа может также потребовать, чтобы чтение выполнялось до окончания ввода целой строки. В процессе ввода обычно выполняется обработка литер сти- рания и отмены. Литера стирания 41= позволяет стирать предыду- щие литеры вплоть до начала строки, а литера отмены @ отме- няет всю набранную строку. Эти две литеры можно заменить другими при помощи системной функции ioctl. Специальный смысл имеет и ряд других литер. Эти литеры перечислены ниже. Они не передаются в читающую программу, если только не был установлен режим ввода без первичной об- работки текста, при котором они теряют свой специальный смысл. А D Формирование признака конца файла для терминала. Все накопленные для чтения литеры немедленно (без ожидания возврата каретки) передаются в про- грамму, а сама литера AD отбрасывается. Если не было накоплено ни одной литеры, функция read вер- нет нуль литер, что является общепринятым при- знаком конца файла. del Посылка сигнала прерывания всем процессам, свя- занным^ данным управляющим терминалом. Если не предусмотрены специальные меры, процессы будут завершены. л\ Формирование сигнала выхода. Этот сигнал ана- логичен прерыванию, за исключением того, что если он не перехвачен, выполняется дампинг па- мяти процесса в файл core текущего оглавления. Дампинг производится только при условии, что файл core существует и имеются полномочия на запись в него или если файл core может быть соз- дан. AS Приостановка вывода на терминал до тех пор, пока не будет введена какая-нибудь литера. AQ Эта литера всегда игнорируется, но в случае, когда она вводится после AS, возобновляется вывод на терминал.
178 Гл. 6. Программирование в системе UNIX При разрыве связи с терминалом всем процессам его группы посылается сигнал «разрыв связи». Этот сигнал формируется например, при исчезновении сигнала с несущей от устройства сопряжения. Если этот сигнал был проигнорирован процессом, то при любом последующем обращении к функции read возвра- щается признак конца файла. Система позволяет устанавливать следующие характеристики терминалов: • Скорость ввода-вывода в бодах. • Паритет при вводе. • Временные задержки для различных литер, таких, как табуляция и новая строка. • Преобразование табуляции в пробелы при вводе и вы- воде. • Литеры стирания, отмены и прерывания. Эти характеристики можно считать и переустановить при помощи системной функции ioctl. Эта функция используется в команде stty. В шестой версии системы UNIX имелись две системные функции — stty (установка характеристик терминала) и gtty (чтение характеристик терминала); в седьмой версии системы они были заменены одной функцией ioctl (управление вводом- выводом). 6.4.5. Транспортеры Два процесса могут обмениваться данными через межпроцессный канал, называемый транспортером. По транспортеру можно пере- давать данные только в одну сторону. Транспортер имеет два конца, представляемых дескрипторами файлов р[0] и р[1], кото- рые получаются в результате обращения к системной функции pipe: int р[2]; pipe (р); Через дескриптор файла р[0] осуществляется чтение из транспор- тера, а через р[1] — запись в транспортер. Значение, возвращае- мое самой функцией pipe, равно 0 при успешном завершении и —1 в противном случае. Если транспортер пуст, то процесс, читаю- щий из него, приостанавливается и будет ждать, пока в транспор- тер не будет записано некоторое количество литер. Аналогично если транспортер заполнен и процесс осуществляет запись в него, то этот процесс будет задержан до тех пор, пока процесс на другом конце транспортера не прочитает некоторое количество литер.
6.5. Процессы 179 Транспортеры обычно создаются общим предком двух процес- сов. Например, при выполнении конвейерной команды а | b оболочка прежде всего создает транспортер, а затем распаралле- ливается с образованием процессов для команд а и Ь. В процессе, созданном для выполнения команды а, стандартный вывод закрывается, а транспортер дублируется и занимает место стан- дартного вывода, как это показано в следующем фрагменте программы: close(l); dup(p[lj); close(p[l]); Системная функция dup возвращает дескриптор файла с наимень- шим свободным номером. Предполагается, что стандартный вы- вод — файл с дескриптором 0 — уже назначен. Аналогичная последовательность действий выполняется и для команды Ь. После того как файлы стандартного ввода и вывода соответствую- щим образом переназначены, для вызова команд а и b исполь- зуется системная функция ехес. Конвейерная форма записи, предоставляемая оболочкой, в большинстве случаев удовлетворяет потребностям пользовате- лей. Однако оболочка позволяет соединять транспортерами толь- ко простую цепочку команд. Более сложные соединения не предусмотрены. 6.5. ПРОЦЕССЫ Согласно терминологии Ритчи и Томпсона (Ритчи, 1978), среда,, в которой выполняется программа, называется образом. Образ включает программу, связанные с ней данные, состояние откры- тых файлов, текущее оглавление. Некоторые атрибуты образов, например идентификатор пользователя и идентификатор группы, доступны пользователю непосредственно, в данном случае через системные функции getuid и getgid. К другим атрибутам, таким, как список порожденных процессов, можно обратиться только косвенно, в данном случае при помощи системной функции wait (ждать). Процесс — это выполнение образа. В системе имеется список поддерживаемых ею процессов. Большинство процессов ожидают либо ввода с терминала или из файла, либо завершения выпол- нения какой-либо системной функции. Список процессов можно распечатать при помощи команды ps. Имеется ограничение (обычно не обременительное) на число одновременно существую- щих процессов как для одного пользователя, так и для всей
180 Гл. 6. Программирование в системе UNIX системы в целом. Размер системной таблицы процессов имеет имя NPROC. Эта величина хранится в исходных модулях системы в оглавлении /usr/sys/h. Ограничение на максимальное число процессов пользователя задается константой MAXUPRC. Для VAX 11/780 типичные значения этих величин — 250 и 50 соот- ветственно. 6.5.1. Исполнение процесса Адресное пространство исполняемого процесса состоит из трех частей: • Код исполняемой программы. Программа часто исполь- зуется совместно несколькими процессами и поэтому защищена от записи. Защита от записи позволяет избе- жать случайного саморазрушения программы (Сопро- граммы не модифицируют свой код). е Сегмент данных, в который пользователь может писать и который не доступен другим пользователям. Эта область начинается сразу за программой. Пользователь может увеличивать или уменьшать размер этой области при помощи системной функции brk. е Не разделяемый стековый сегмент, который располага- ется, начиная от верхней границы памяти, и растет вниз х). Эта область автоматически расширяется по мере надобности. Адресное пространство каждого процесса отлично от адрес- ного пространства других процессов в системе. Взаимодействие между процессами может осуществляться через транспортеры и сигналы. Для управления процессами служат четыре системные функ- ции: fork, ехес, wait и exit. 6.5.2. Системная функция fork Системная функция fork («вилка») порождает две почти идентич- ные копии процесса. Одна из этих копий называется родитель- ским процессом (родителем), а другая — порожденным процес- сом (потомком). Родительскому процессу функция fork возвра- щает номер порожденного процесса, а значение, возвращаемое в порожденный процесс, равно нулю. Если функции fork не уда- лось создать новый процесс, возвращается значение —1. Это может случиться, например, при переполнении системной таб- лицы процессов или если при выполнении fork произошло пре- рывание. От больших адресов к меньшим.— Прим. ред.
6.5. Процессы 181 Порожденный процесс наследует все компоненты образа роди- тельского процесса, включая открытые файлы. Новый процесс имеет свой собственный сегмент данных и стек. Единственными совместно используемыми родителем и потомком ресурсами яв- ляются файлы, которые были открыты в момент распараллелива- ния родительского процесса. Это не вызывает никаких проблем в случае, если родительский процесс ожидает завершения работы потомка. Однако если порожденный процесс исполняется парал- лельно с родительским, то должно соблюдаться некоторое со- глашение о том, кому принадлежат эти открытые файлы. Например, когда оболочка выполняет команду а & она при помощи функции fork создает новый процесс, а затем переназначает в нем стандартный ввод на файл /dev/null. Тем самым оболочка сохраняет за собой ввод с терминала. 6.5.3. Системная функция wait После создания (при помощи функции fork) нового процесса родительский процесс имеет выбор: он может либо исполняться далее параллельно с потомком, либо подождать завершения ра- боты потомка. Системная функция wait приостанавливает обратившийся к ней процесс до тех пор, пока не завершится один из его потом- ков. Если потомков несколько, то порядок их завершения не определен, поэтому для ожидания завершения исполнения конкретного процесса требуется выполнить следующий цикл: int status; /*статус завершения*/ int childpid; ^идентификатор потомка*/ while (wait(&status)!=childpid) Нельзя предполагать, что процессы, о завершении которых сооб- щает функция wait, были порождены выполняемой в данный момент программой. Программа может унаследовать порожден- ные процессы от предыдущего пользователя процесса, так как одна программа может, обратившись к функции fork, создать про- цесс, а затем при помощи функции ехес вызвать другую про- грамму. Ожидать завершения работы порожденных процессов может только их родительский процесс. Если родитель завершает ис- полнение, его потомки наследуются процессом 1.
182 Гл. 6. Программирование в системе UNIX 6.5.4. Системная функция ехес Системная функция ехес замещает выполняемую в данный мо- мент программу новой программой и начинает выполнять ее, передавая управление на ее точку входа. Идентификатор про- цесса функцией ехес не меняется. В случае успешного заверше- ния возврата из функции ехес не бывает, а образ вызывающей программы теряется. Имеются несколько разновидностей функ- ции ехес. Простейшая из них имеет вид int execv(name, argv) char *name; char *argv[J; Параметр name задает имя файла, содержащего программу, ко- торую требуется выполнить (файл типа a.out), a argv — вектор из указателей на параметры — цепочки литер, которые будут переданы в вызываемую программу. Вектор завершается нуле- вым указателем. По соглашению, argv[0] является именем вы- полняемой команды. Вторая разновидность функции ехес описывается как int execl(name, arg0, argn ..., argn, 0); и позволяет задавать параметры явным образом. После выполнения ехес открытые файлы остаются открыты- ми, если только при помощи функции ioctl не установлена соот- ветствующая опция. Это позволяет родителю (например, оболоч- ке) открывать файлы для потомка. Неизменными остаются и со- стояния сигналов. Исключение составляют перехватываемые сигналы — в этом случае состояние сигнала сбрасывается в ну- левое. Не изменяются функцией ехес и действительные идентифи- каторы пользователя и группы п. Однако если среди полномочий заданного для выполнения файла имеется установка идентифи- катора владельца (или установка идентификатора группы), то в качестве эффективного идентификатора пользователя (груп- пы) устанавливается идентификатор владельца (группы) данного файла. Рассмотрим пример. Программа-оболочка перед обращением к функции ехес выполняет переадресацию ввода-вывода путем закрытия и открытия файлов. Если команда запускается как фо- новая, то в качестве стандартного ввода открывается файл /dev/null. Это позволяет избежать путаницы при вводе с терми- нала. Отключаются и порождаемые с терминала сигналы. Х) Действительный идентификатор пользователя (группы) определяет, по чьей инициативе запущен процесс. Эффективный идентификатор пользователя (группы) определяет, чьими правами пользуется процесс.— Прим, перев.
6.5. Процессы 183 Наиболее вероятная ошибка при выполнении ехес заключает- ся в том, что файл с указанным именем name не существует или не является выполнимым. Другая распространенная причина не- удачного завершения ехес, которая особенно часто возникает при использовании литеры * для порождения имен файлов в обо- лочке,— слишком большой список параметров (более 5120 байт). Среди прочих причин — недостаток адресного пространства для инициирования процесса (это более вероятно на PDP 11/45 или 11/70, чем на VAX 11/780). В большинстве программ нет надобности в управлении про- цессом — эту работу может выполнять оболочка, интерпретируя командные процедуры. Если в программе требуется выполнить подкоманду, можно с успехом воспользоваться подпрограммой system из библиотеки стандартных С-программ. 6.5.5. Системная функция exit Процесс может прекратить выполнение (завершиться) либо до- бровольно, обратившись к системной функции exit, либо прину- дительно, получив сигнал. Параметр функции exit трактуется int status, signal; while (wait(istatus) !* childpid) if (status&0200) { /♦ Образован файл core*/ } if (status — 0177) ( /♦ Порожденный процесс приостановлен, но может быть * возобновлен. Этот статус предназначен главным образом для ♦ отладчиков, которые используют для управления другим ♦ процессом системную функцию ptrace } ♦/ signal - status&0177; if (signal —- О) { гс - (status »8)&0377; < /♦ Процесс завершился нормально, Гс • статус завершения. }else{ / * Процесс завершился аварийно, по сигналу ♦ / Рис. 6.9 Анализ статуса завершения процесса
184 Гл. 6. Программирование в системе UNIX как статус завершения процесса. По соглашению, нуль означает успешное завершение, а отличное от нуля значение — аварийное завершение. По статусу завершения процесса, который возвращается ро- дителю функцией wait, можно распознать различные ситуации. На рис. 6.9 показана программа, анализирующая статус завер- шения процесса. Предполагается, что childpid содержит иденти- фикатор порожденного процесса. Данный фрагмент программы выполняется родительским процессом. 6.5.6. Среда процесса Параметры argv и argc функции main позволяют обращаться к яв- ным (позиционным) параметрам, заданным в обращении к ехес. Когда программа начинает выполнение, ехес передает ей допол- нительно еще один массив цепочек литер, называемый средой процесса. Наиболее часто используемые переменные среды были рассмотрены в гл. 4. По соглашению, эти цепочки литер имеют вид имя=значение Приведенная выше функция execv передает эту среду в неизме- ненном виде. Измененную среду можно передать в вызываемую программу при помощи функции execve: int execve(name, argv, envp) char «name; char «argv[ ]; char *envp[ ]; Параметр envp представляет собой вектор указателей на цепочки литер, содержащие среду. Этот вектор завершается нулевым указателем. Среда доступна в вызываемой программе через внешнюю переменную environ, описываемую как char ««environ; В программах на языке С значения переменных среды можно получить при помощи подпрограммы getenv, описание которой имеет вид char «getenv(name) char «name; Подпрограмма getenv ищет в среде цепочку вида имя=значение и возвращает указатель на значение, если имя name найдено. В противном случае возвращается нуль.
6.6. Сигналы и прерывания 185 6.6. СИГНАЛЫ И ПРЕРЫВАНИЯ Программа получает уведомление о различных событиях через аппарат асинхронных сигналов. Примером такого события может служить нажатие клавиши break на терминале. Среди прочих событий — программные ошибки (например, нарушение защиты памяти) и сигнал из другой программы (kill). Обычной реакцией на сигнал является завершение процесса. За исключением SIGK1LL, сигналы могут либо игнорироваться, либо вызывать переход на заданную С-функцию в программе. После некоторых сигналов (см. приведенный ниже список) содержимое файла core позволяет проанализировать ошибочную ситуацию с помощью отладчика adb или sdb. Можно предотвратить запись в файл core, например создав его без права записи. 6.6.1. Сигналы Ниже приведен полный перечень сигналов. Имена сигналов оп- ределены в системном файле заголовков <signal.h>. Сигналы, но- мера которых помечены звездочкой, вызывают запись дампа в файл core, если они не перехватываются или не игнорируются. 1 SIGH UP Разрыв связи с терминалом. Обычно возбуждается при исчезновении несущей в телефонном канале связи, но может быть также сгенерирован путем выполнения stty 0 >/dev/tty 2 S1GINT Прерывание от терминала. Происходит при нажатии кла- виши del или break на клавиатуре терминала. 3* SIGQUIT Сигнал выхода. Возбуждение этого сигнала является обычным способом завершения работы программы в слу- чае, если требуется дамп памяти. Генерируется с тер- минала путем ввода литеры «разделитель файла» л\. 4* SIGILL Попытка выполнить нелегальную машинную команду. 5* SIGTRAP Трассировочное прерывание (используется отладчиком adb). 6* SIG ЮТ Выполнение машинной команды ЮТ (используется от- ладчиком adb). Этот сигнал иногда называется выбросом. 7* SIGEMT Выполнение машинной команды ЕМТ. Используется в не- которых машинах, не имеющих арифметики с плаваю- щей точкой.
186 Гл. 6. Программирование в системе UNIX 8* SIGFPE Исключительная ситуация (переполнение или деление на нуль) при выполнении операций с плавающей точкой. 9 SIGK1LL Уничтожение процесса. Этот сигнал можно использовать для того, чтобы заведомо избавиться от любого своего процесса. Он не может быть ни перехвачен, ни проиг- норирован никаким процессом. 10* SIGBUS Ошибка шины. Этот сигнал обычно возбуждается из-за ошибки в косвенной адресации с использованием указа- теля в С-программе. 11* SIGSEGV Обращение за пределы сегмента. Этот сигнал может возникнуть также из-за ошибки в косвенной адресации или же из-за выхода за пределы сегмента. 12* SIGSYS Неправильный параметр при обращении к системной функции. Этот сигнал не должен появляться, если про- грамма написана на языке С. 13 SIGPIPE Запись в транспортер, из которого некому читать. Это происходит, если получатель завершает работу, остав- ляя пишущую сторону с разорванным транспортером. 14 SIGALRM Сигнал от таймера. Генерируется после обращения к системной функции pause (см. приложение 2). 15 SIGTERM Сигнал программного прерывания. Этот сигнал посы- лается по умолчанию командой kill. Он предоставляет получившему его процессу возможность уничтожить временные файлы и благополучно завершить работу. Если простая команда kill не уничтожила процесс, попробуйте послать сигнал SIGK1LL командой kill —9. 6.6.2. Посылка сигналов Команда kill посылает сигнал процессу с тем же самым эффектив- ным идентификатором пользователя, обращаясь к системной функции kill: int kill(pid, sig) int pid; int sig; которая посылает сигнал sig процессу с номером pid. Если pid равен нулю, сигнал посылается всем процессам, имеющим гот же
6.6. Сигналы и прерывания 187 самый эффективный идентификатор пользователя. Если sig лежит вне допустимого диапазона либо если указанного процесса не существует, функция kill возвращает значение —1. При помощи kill можно послать сигнал только процессам, имеющим тот же самый эффективный идентификатор пользователя. 6.6.3. Перехват сигналов Процесс может либо перехватить сигнал, либо полностью его проигнорировать, либо позволить системе выполнить по сигналу подразумеваемое действие. Если не предприняты специальные меры, все сигналы вызывают завершение работы получающего их процесса. Заказать перехват сигнала, его игнорирование или вос- становить подразумеваемую реакцию на него позволяет систем- ная функция signal. При перехвате сигнала управление пере- tfinclude <signal.h> int sigcnt; handler(a) /♦ Значением 'а' является SIGINT. *! { /♦ Сбросить сигнал для того, чтобы его можно было ♦' /♦ перехватить снова signal (a, handler); / ♦ Зарегистрировать прерывание и возвратить работу */ sigcnt ++; } mainO signal(eiGINT, handler); } Рис. 6.10 Обработчик сигнала дается заданной пользователем С-функции, называемой обработ- чиком сигнала. Например, программа, приведенная на рис. 6.10, обрабатывает сигнал SIGINT при помощи функции handler. При получении сигнала эта функция вызывается с параметром — номером сигнала. В данном примере подсчитывается, сколько раз произошло прерывание от терминала.
188 Гл. 6. Программирование в системе UNIX После перехвата сигнала реакция на него, как правило, из- меняется на подразумеваемую. Если требуется перехватывать сигнал при каждом его возбуждении, в обработчике должно быть еще одно обращение к функции signal. Чтобы восстановить подра- зумеваемую системную реакцию на сигнал SIGI NT, нужно об- ратиться к функции signal следующим образом: signaI(SIGINT, SIG_DFL); Установка режима полного игнорирования того же сигнала вы- полняется так: signal(SIGI NT, SIG_IGN); Функция signal возвращает предыдущее состояние указанного сигнала. Помимо сказанного выше, нормальное выполнение программы может быть нарушено только из-за неудачного завершения обра- щений к системным функциям. Вызов системной функции можно повторить, если кодом ошибки в еггпо является EINTR. Про- грамма ср на рис. 6.5, например, при прерывании все-таки пе- чатает сообщение об ошибке. Этого можно избежать при помощи оператора if(errno != EINTR) еггог("..."); 6.6.4. Фоновые процессы При выполнении функции fork порождаемый процесс наследует состояния сигналов своего родителя. По соглашению, если в на- чале работы процесса (после ехес) сигнал находился в состоянии игнорирования, его состояние никогда не изменяется. Это позво- ляет запускать с терминала процессы, которые будут затем вы- полняться как фоновые, и на них не будут оказывать никакого воздействия сигналы прерывания и выхода, возбуждаемые с тер- минала. Чтобы это соглашение не нарушалось даже на короткое время, при установке сигналов используется следующий надеж- ный прием: if (signal(SIGI NT, SIG_IGN)! = S1G_IGN) signal(SIGI NT, handler); Тем самым сигнал с состоянием SIG___IGN всегда остается в том же состоянии. Для выполнения подкоманды в С-программе можно восполь- зоваться подпрограммой system, приведенной на рис. 6.11. Во время ожидания завершения работы порожденного процесса сиг- налы прерываний (и выхода) игнорируются; порожденный про- цесс наследует состояния этих сигналов от родителя. После за-
6.6. Сигналы и прерывания 189 вершения порожденного процесса в родительском процессе вос- станавливаются первоначальные состояния сигналов и осуществ- ляется возврат из подпрограммы. #include <signal.h> int system(name, argv) char *name; char ♦argvf]; int pid; int status; int del; int quit; f * игнорировать сигналы в родительском процессе ♦ / del = signaKSIGINT, SIGJGN); quit ~ signal(SIGQUIT, sTgJGN); switch (pid « fork()) { case 0; /♦ Выполняется порожденным процессом *7 /*. сбрасываются сигналы в порожденном процессе ♦ signaKSIGINT, del); signal(SIGQUIT, quit); exec(name, argv); / * Неудачное завершение exec в порожден - ♦ / J*ном процессе */ / * причина - в еггпо ♦ / exit(1); case —1: /* Неудачное завершение fork ♦ / status ~ 0; break; default: 7 * Ожидание завершения порожденного процесса ♦ f / ♦ Выполняется родительским процессом while (wait(&status)!*=pid); } signaKSIGINT, del); signaKSIGQUIT, quit); return(status); 1 Рис. 6.11 Подпрограмма system
ГЛАВА 7 ПОДГОТОВКА ДОКУМЕНТОВ Подготовка текстов, писем, докладов и книг — трудоемкий процесс, требующий большого внимания к мелочам. Система UNIX предоставляет средства, облегчающие подготовку докумен- тов. Среди этих средств — программы форматирования текстов, которые позволяют задавать размер страницы, длину строки, поля, интервал между строками ц шрифты. Другие средства, используемые совместно с этими форматорами текстов, позволяют печатать таблицы и математические формулы. Перечисленные средства вместе с редактором текстов значи- тельно облегчают подготовку первого варианта и последующую корректировку документов. Имеются также программы для вы- явления орфографических ошибок, создания предметных указа- телей, обнаружения плохо или неправильно построенных фраз. В целом при умеренных затратах можно получить довольно качественный результат. Если же подходящего средства нет, его часто можно сравнительно легко создать, воспользовавшись методами, описанными в этой главе. 7.1. ФОРМАТОРЫ ТЕКСТОВ nroff И troff Основными инструментами для подготовки документов являются форматоры текстов troff (произносится ти-роф) и nroff. Для вы- вода текста на устройства типа пишущей машинки используется nroff, а для печати с полиграфическим качеством используется troff. Обе программы произошли от более раннего форматора текстов roff, имеющегося в системе CTSS (Крисмэн, 1965). Вход- ные данные содержат как текст самого документа, так и инструк- ции, задающие желаемый формат вывода. Вывод может выпол- няться на различные устройства, начиная с простейших терми- налов, работающих в коде ASCII, и кончая фотонаборными уст- ройствами с высокой разрешающей способностью. Большая часть этой главы посвящена описанию форматора nroff, который ис- пользуется главным образом для вывода текста на устройства
7.1. Форматоры текстов nroff и troff 191 типа пишущей машинки (например, DASI-450 или Diablo Hi- term) и на построчные печатающие устройства. С небольшими оговорками nroff и troff совместимы, и для них может исполь- зоваться один и тот же входной текст. Документы можно печа- тать на самых разнообразных устройствах, в том числе на мат- ричном печатающем устройстве (например, Versatec V80), ла- зерном печатающем устройстве Imagen или на фотонаборном уст- ройстве (например, APS-5). Все, что говорится в этой главе о форматоре nroff, относится также и к форматору troff. Форматор troff упоминается только при описании возможностей, отсутствующих в nroff (например, изменение типа шрифта). Если встретился запрос, имеющийся только в troff, nroff обычно пропускает его и продолжает обра- ботку. Список запросов форматора troff приведен в приложе- нии 7. Форматор nroff позволяет управлять процессом форматиро- вания текстов, в частности задавать размер страниц, длину строк и интервал между строками, а также предоставляет средства, позволяющие перемещаться по странице по горизонтали и по вертикали произвольным образом, делать отступы и выполнять табулирование. Можно также устанавливать режим с заполне- нием строк (с выравниванием по правому краю или без выравни- вания) и задавать способ переноса. Форматор troff помимо этого позволяет управлять типом шрифта и размером литер и обладает более высокой разрешающей способностью. В nroff можно непосредственно воспользоваться всеми этими средствами форматирования. Кроме того, имеются средства, позволяющие писать программы для nroff. Предусмотрены тек- стовые переменные и условные запросы, а также числовые ре- гистры и обычные арифметические операции. Можно описывать макроопределения и обращаться к ним; это позволяет создавать библиотеки запросов. Можно устанавливать ловушки, позволяю- щие выполнять заранее определенную последовательность запро- сов при достижении заданного места на странице. Текст можно перенаправить в поименованный буфер, что позволяет накапли- вать примечания и выводить их в конце страницы. 7.1.1. Основные принципы подготовки документов Данные, передаваемые для обработки форматору troff, содержат как собственно текст документа, так и инструкции (или запросы), описывающие, в каком виде должен быть распечатан этот текст. Запросы форматора troff начинаются со специальной литеры: точки . или апострофа ' . Даже если в тексте нет ни одного запроса, troff все равно будет форматировать его некоторым подразумеваемым образом. Для получения вывода в требуемом
192 Гл. 7. Подготовка документов виде можно было бы затем добавить необходимые запросы. Такой подход редко используется. Документы подготавливаются с ис- пользованием пакетов запросов, которые обеспечивают обработ- ку абзацев, колонтитулов, иллюстраций и названий разделов. Перед тем как ввести документ в машину, вы должны опреде- лить его формат и выбрать пакет макроопределений, который бу- дете использовать. Имеются пакеты макроопределений общего назначения, которые пригодны для широкого круга приложений. Например, в фирме Bell Laboratories для подготовки внутренней документации используются библиотеки —ms и —mm. Пакет —ms поставляется вместе с системой UNIX. Он описан в прило- жении 10. В вашей организации может существовать свой собст- венный пакет, отвечающий ее потребностям. Для оформления заголовков, абзацев и иллюстраций следует использовать макроопределения. Например, при подготовке английского оригинала этой книги для создания заголовков ос- новных разделов использовался запрос вида . SH 2.1 Для того чтобы создать абзац без отступа, в строке, предшествую- щей тексту этого абзаца, ставится запрос .LP Аналогично ,РР ставится перед абзацем с отступом в первой строке. Сдвинутый вправо абзац с висячей меткой (а) вида (а) можно было бы записать как .IP (а) Эти макроопределения аналогичны макроопределениям из макро- пакета —ms. Однако, для того чтобы стиль книги соответствовал стилю издательства, в эти макроопределения были внесены неко- торые изменения. Использование макроопределений позволяет откладывать окончательный выбор формата текста и впоследствии менять его в зависимости от текущих потребностей. Меняя макропакет сле- дует проявлять осторожность при использовании запросов самого форматора nroff. Где это возможно, к ним лучше не прибегать, поскольку это может повлиять на работу макропакета. В любом
7.1. Форматоры текстов nroff и troff 193 случае проверьте сначала, нет ли в макропакете нужного вам средства. Эта глава знакомит с некоторыми из возможностей, предо- ставляемых форматорами nroff и troff, в том числе с библиотекой макроопределений, использовавшейся при подготовке этой кни- ги. В этой главе содержатся также сведения о nroff и troff, до- статочные для подготовки несложных документов, таких, как письма и диаграммы. Однако написание макроопределений nroff для сложных задач форматирования (например, для вывода в две колонки) требует более глубокого знания системы и под силу только хорошо разбирающимся в nroff и troff программистам. При подготовке документов для nroff рекомендуется избегать длинных строк. Каждое предложение следует начинать с новой строки и завершать строку на каждом знаке препинания. Это поз- воляет легко вносить изменения. Документ большого размера следует размещать в нескольких файлах. Например, каждая гла- ва этой книги хранилась в отдельном файде, что позволяло легко устанавливать принадлежность текста некоторой главе при использовании средств типа grep. Форматирующие макрозапросы вставляются прямо в текст документа. Документы можно составлять или непосредственно за терминалом, или вводить их с рукописи автора, вставляя, где надо, макрозапросы. Вызов форматора nroff Форматор nroff вызывается командой nroff [ опции ... ] документ Весь, документ будет распечатан, начиная, по умолчанию, со страницы с номером 1. Приведем некоторые из имеющихся опций: —ms Использовать макропакет, определяемый s. —пр -Установить номер первой страницы равным р. —о список Распечатать только страницы с номерами, задан- ными в списке. —sn Делать останов после печати каждых п страниц. Например: troff —оЗ—5,8,12— chapterl или nroff —si chapter4 По опции —о распечатываются только перечисленные в списке страницы. В первом примере будут распечатаны страницы с 3-й по 5-ю, 8-я и с 12-й до конца документа. Во втором примере 7 С. Баурн
194 Гл. 7. Подготовка документов использование опции —si приведет к тому, что nroff будет при- останавливать печать после каждой страницы и ждать нажатия клавиши возврата каретки для продолжения работы. Этим можно воспользоваться, например, когда требуется в пишущую, машин- ку заправлять отдельные листы специальной бумаги. 7.1.2. Простые запросы В простейшем случае nroff считывает входные строки до тех пор, пока не будет накоплено достаточное количество слов для запол- нения одной выходной строки. Если входная строка начинается с пробела, то все, что было накоплено, выводится, и начинает накапливаться новая строка; в начало этой строки помещается то же количество пробелов. Новая выходная строка также начи- нается в случае, если встречается пустая входная строка. Запросы форматора nroff записываются в отдельной строке и начинаются литерой . в первой позиции этой строки. На- пример, .sp эквивалентно пустой входной строке. Функции аналогичны запросам; они могут помещаться внутри строк текста и вводятся литерой \ . Например, комментарий для nroff записывается при помощи литер \'' : .sp \"вывод пустой строки Все запросы и функции вставляются в текст документа. Их имена состоят из одной или двух литер. Для имен макро справедливо то же правило. Запросы могут иметь один или более параметров, разделенных пробелами. По запросу .sp 5 будет пропущено 5 строк, и вывод возобновится о начала новой строки. Обычно строки выводятся через один интервал. При подго- товке проекта документа вывод через два интервала оставляет место для внесения правки. Запрос .1s 2 устанавливает вывод строк через два интервала. Вывод через один интервал можно восстановить, воспользовавшись запросом •1s 1
7.1. Форматоры текстов nroff и troff 195 Строки можно центрировать с помощью запроса .се. Напри- мер, .се 4. Оболочка порождает заголовок 4. Оболочка При помощи запроса .се с целым числом в качестве параметра можно центрировать несколько последовательных строк. В nroff заголовок можно подчеркнуть, воспользовавшись запросом .ul, например: .се .ul 4. Оболочка В troff по этому запросу заголовок будет напечатан курсивом: 4. Оболочка Управление полями Можно управлять размером как левого, так и правого полей страницы. Поле слева изменяется запросом отступа границы .in. Например, .in 4 сдвинет левый край в позицию четвертой литеры в строке. Запрос .in 4-4 увеличит отступ на 4 позиции, а .in —4 уменьшит этот отступ на 4 позиции. В начале абзаца первая строка часто сдвигается относительно остальных строк. Запрос временного отступа .ti выполняет заданный сдвиг только для одной следующей выходной строки. Например, .ti 4-3 сдвинет левый край строки на 3 позиции вправо. Полем справа можно управлять, задавая длину строки. Запрос .11 4i установит длину выводимых строк, равную 4 дюймам. Перво- начальная длина строк — 6.5 дюйма. Длину строк можно уве- 7*
196 Гл. 7. Подготовка документов личить или уменьшить, используя знаки + или —. Например, запрос .11 -8 укоротит строку на 8 литер. Заполнение и выравнивание строк Когда nroff накопит достаточное количество слов для того, чтобы заполнить одну выходную строку, выполняется выравнивание строки по правой границе, после чего строка выводится. Для выравнивания между словами вставляются пробелы. В форма- торе troff расстояние между словами может быть очень малень- ким, равным одной трети ширины буквы т. Запрос .па устанавливает режим вывода строк без выравнивания по правому краю. В этом режиме дополнительные пробелы между словами не вставляются. Для восстановления режима выравнивания по правому краю используется запрос .ad Запрос .nf отменяет режим заполнения выводимых строк. После этого запроса выводимые строки не заполняются и не выравниваются. Вхюдные строки копируются в неизменном виде в файл вывода независимо от их длины и расстояний между словами. Режим заполнения строк восстанавливается запросом .fi Для того чтобы разбить выводимый текст на две строки, исполь- зуется запрос .Ьг. Этот запрос вызывает разрыв строки', теку- щая строка выводится, и начинается накопление новой строки. Для того чтобы правильно расположить выводимый текст относительно физической страницы, всю страницу можно сме- стить при помощи запроса • .ро Первоначально смещение страницы устанавливается равным О в системе nroff и 26/27 дюйма в системе troff. Соотношение между запросами, задающими длину строки, сдвиг края, центрирование и смещение страницы показаны на рис. 7.1. Длина строки измеряется от левого края страницы до правого. Текущий сдвиг также отсчитывается от левого края.
7.1. Форматоры текстов nroff и troff 197 Запросы 11, in и ро без параметров восстанавливают предыду- щие значения соответствующих величин. Запоминается только одно предшествующее значение, поэтому вложенность лучше всего выражать увеличением и уменьшением соответствующих величин на некоторое число. DO in | се II Рис. 7.1 Поля в системе nroff Форматор nroff при выводе обычно выполняет перенос слов. Перенос слов во всем последующем тексте можно запретить за- просом .nh Запрос .hw слово запрещает перенос одного конкретного слова. Можно также задать предпочтительные варианты переноса слова, например: .hw in—di—vid—ual Размещение текста no вертикали Смещение по вертикали можно задавать либо относительно теку- щей позиции, либо относительно начала текущей страницы. Например, запрос .sp 1.5i выполняет сдвиг на 1.5 дюйма вниз относительно текущей по- зиции, а запрос .sp |1.5i выполняет сдвиг на 1.5 дюйма относительно верхнего края теку- щей страницы. Для того чтобы сдвинуться назад на одну строку, задается отрицательное расстояние, например: .sp —1 Обычно размер страницы устанавливается по умолчанию равным 11 дюймам (28 см); его можно изменить запросом .pl Сдвиги разрешается выполнять только в пределах текущей страницы.
198 Гл. 7. Подготовка документов Поскольку ряд устройств не выполняет сдвиг назад или на полстроки вперед, предусмотрен специальный фильтр col, кото- рый буферизует страницу и печатает строки в нужном порядке. Расстояния Допустимый размер сдвигов, выполняемых при выводе, опреде- ляется разрешающей способностью устройства вывода. Построч- ное печатающее устройство допускает сдвиг только на одну строку, в то время как устройство Diablo Hiterm имеет вертикаль- ное разрешение в 1/48 дюйма. Фотонаборное устройство CAT, которое использовалось первоначально при разработке troff, имеет разрешающую способность 1/144 дюйма по вертикали и 1/432 дюйма по горизонтали. Единица измерения расстояния, используемая в troff, зависит от устройства вывода. Для устрой- ства APS-5, которое использовалось при подготовке английского оригинала данной книги, эта величина равна 1/723 дюйма. Для nroff единица расстояния равна 1/240 дюйма. В запросах, в которых задаются расстояния, можно исполь- зовать единицы, указанные в таблице. Таблица 7.1 Единица Смысл Размер i дюймы с сантиметры 1/2.54 дюйма Р пункты 1/72 дюйма Р цицеро 1/6 дюйма и базисные единицы зависит от устройства m эм ширина буквы m п эн ширина буквы п (1/2 эм) V расстояние между стро- ками переменный Если единица измерения не задана, подразумеваемое значение зависит от запроса. Для запросов, управляющих размещением текста по горизонтали, используется размер буквы т(эм). В сис- теме troff размер единицы эм зависит от текущего размера букв.
7.1. Форматоры текстов nroff и troff 199 В запросах, управляющих размещением текста по вертикали, под- разумеваемой единицей измерения является расстояние между строками. Расстояние между строками можно также изменить, используя запрос .vs (см. ниже). Разрешается использование десятичных дробей и арифметических действий. Полученные результаты всегда округляются в соответствии с разрешающей способностью устройства вывода. Внутри выражений допускают- ся круглые скобки и арифметические операции +, —, /, * и % (взятие остатка от деления). В системе nroff все операции имеют равный приоритет; следует использовать круглые скобки. Поскольку nroff округляет расстояния в соответствии с раз- решающей способностью по горизонтали или по вертикали, могут возникнуть погрешности, в особенности когда используются спе- цификации в абсолютных единицах, например: .sp 16.7511 Табуляции и колонки Таблицы и колонки на рисунках иногда бывают достаточно про- стыми, и их можно форматировать, используя непосредственно nroff. Однако обычно лучше воспользоваться препроцессором, таким, как tbl, предназначенным специально для подготовки таблиц. Символ табуляции во входной строке преобразуется при выводе в последовательность пробелов с таким расчетом, чтобы последующий текст попал в следующую колонку. По умолчанию позиции табуляции устанавливаются в системе nroff через каж- дые 8 литер, а в troff — через каждые 0.5 дюйма. Табуляции можно переустанавливать. Например, Ла 8 40 60 установит позиции табуляции на расстоянии 8, 40 и 60 эм. Если текст уже миновал позицию табуляции, то на пишущих машинках с механическим табулятором каретка автоматически передви- гается до следующей позиции табуляции. Система nroff ведет себя аналогично. По умолчанию, колонки выравниваются по левому краю. Для колонок чисел предусмотрена возможность выравнивания по правому краю; имеется также возможность центрирования колонок. Например: •nf Ла .5i 1.51 3.5iR .ul ф Фамилия ф Поставщик ф Цена ф Kubik ф Computer Technology ф $183 ф Anderson ф System Memories ф $79 .fi
200 Гл. 7, Подготовка документов В этом примере (ф обозначает символ табуляции) третье поле будет выровнено по правому краю относительно позиции, находя- щейся на расстоянии 3.5 дюйма: Фамилия Поставщик Цена Kubik Computer Technology $183 Anderson System Memories $79 Для центрирования поля используется спецификация С. Для заполнения позиций между колонками обычно исполь- зуется пробел, однако можно заменить его на другую литеру, воспользовавшись запросом tc. Например, в результате выпол- нения .nf Ла 20 .ul ФамилияфТелефон .tc. Hal Alles ф ХХХХ .fi будет напечатано Фамилия Hal Alles..... Телефон ХХХХ Команда Лс без параметров восстанавливает пробел в качестве литеры, используемой для заполнения позиций между колон- ками. Команда .nf в начале таблицы отменяет режим заполнения строк. Управление страницами Размер страницы обычно равен 11 дюймам. Его можно изменить запросом установки размера страницы, например: .pl 6i Для того чтобы прервать заполнение текущей страницы и начать новую, можно воспользоваться командой .Ьр. Прерывания стра- ниц обычно используются в ловушке конца страницы (см. разд. 7.1.3). При выводе таблицы может оказаться необходимым, чтобы вся таблица размещалась на одной странице. Для этого исполь- зуется запрос .пе. Например, по запросу .пе 6 вывод будет продолжаться в текущую страницу, если в ней может поместиться еще не менее 6 строк; в противном случае выполняется переход на следующую страницу.
7.1. Форматоры текстов nroff и troff 201 Колонтитулы Запрос .tl печатает колонтитул, состоящий из трех частей. Первая часть выравнивается по левому краю, вторая центри- руется, а последняя выравнивается по правому краю. Например, запрос .tl 'Февраль 3, 1982'ПРОЕКТ'Глава 7' напечатает Февраль 3, 1982 ПРОЕКТ Глава 7 В качестве ограничителя можно использовать любую литеру (в данном случае '). Ограничителем является первая встретив- шаяся после имени запроса литера, отличная от пробела и ли- теры табуляции. Длина строки и длина колонтитула не зависят друг от друга. Текущий отступ не влияет на колонтитул, однако колонтитул зависит от смещения страницы. Для установки длины колонти- тула служит запрос .It. 7.1.3. Дополнительные возможности Макро Макро позволяет задать имя для группы запросов или некоторого фрагмента текста и вызывать их по этому имени. Макро следует определять до его использования, так как макрозапросы с неоп- ределенными именами игнорируются. При написании макро- определения можно использовать уже описанные макроопреде- ления. Например, при подготовке английского оригинала этой книги для оформления абзацев первоначально использовалась последовательность запросов .sp .ti 4 .ne 2 задающая пропуск одной строки и отступ длиной 4 эм в первой строке абзаца. Эти запросы составили макроопределение РР: .de РР •sp .ti 4 .ne 2 Первая строка .de РР является началом макроопределения и за- дает имя макро — РР. Конец макроопределения обозначается
202 Г л. 7. Подготовка документов литерами .., помещаемыми в отдельной строке. В эту строку нельзя включать комментарий. Каждый абзац в последующем тексте теперь начинается с вызова РР, например: .РР Во многих макробиблиотеках... Во многих макробиблиотеках для имен макро используются прописные буквы, что позволяет избежать совпадения этих имен с зарезервированными именами форматора nroff. При определе- нии новых запросов следует избегать употребления имен, исполь- зуемых в самой системе troff или в вашей макробиблиотеке. Для получения списка имен, определенных в библиотеке, можно вос- пользоваться запросом .pm. В макрозапросах можно задавать параметры; они помещаются в той же строке, что и вызов. Например, макроопределение, форматирующее заголовки разделов английского оригинала этой книги, вызывается так: .SH 7.2 "Получение итогового документа" Параметры разделяются пробелами. Еслй внутри параметра со- держится пробел или символ табуляции, этот параметр можно заключить в двойные кавычки. В данном примере первым пара- метром является 7.2, а вторым — Получение итогового документа. В макроопределении можно использовать до 9 параметров; они доступны как \$1, \$2, ... . Если параметр не задан при вызове, его значением считается пустая цепочка литер. В данном примере SH определяется следующим образом: .de SH \"заголовок раздела: .SH номер-раздела название .sp \\$2 В этом макроопределении содержится также комментарий, введенный с помощью литер \", в котором описано назначение макро и его параметры. . Макроопределение считывается дважды: когда оно опреде- ляется и когда его вызывают. В обоих случаях по'мере считыва- ния текста макро выполняются запросы форматора nroff. В при- веденном выше определении макрозапроса SH для того, чтобы предотвратить интерпретацию \$1 во время первого просмотра макроопределения, перед\$1 требуется поместить литеру \. Далее, если бы первым параметром был запрос форматора nroff, скажем .Ьр, произошел бы разрыв печати страницы. Литера авто- регистра \& служит для того, чтобы скрыть действие точки в начале строки.
7.1. Форматоры текстов nroff и troff 203 Пара двойных кавычек внутри параметра, заключенного в двойные кавычки, передается в макроопределение как одна двой- ная кавычка, например: .SH ... "Обработка литеры "" в системе troff" Страничные ловушки Описанные выше запросы позволяют легко форматировать обыч- ный текст, однако вскоре возникает потребность в средствах уп- равления страницами. Никаких готовых средств для формирова- ния колонтитулов вверху и внизу страниц nroff не предоставляет. Вместо этого можно установить ловушку на определенную по- зицию по вертикали внутри страницы. При достижении этой позиции выполняется заданный запрос. Часто устанавливаются две ловушки, одна в начале страницы .wh 0 ... а другая недалеко от конца страницы. Например, .wh —5 РЕ устанавливает ловушку на расстоянии 5 строк от конца каждой страницы. После того как выведется строка, отстоящая на 5 строк от конца страницы, выполняется макрозапрос РЕ. Макроопре- деление конца страницы РЕ описывается отдельно от определения ловушки. Например, в макроопределении .de РЕ 'sp 2 Л1 руководство по UNIX: Г я редакция 1971: Стр %: Ър задаются пропуск двух строк и печать колонтитула. В качестве ограничителя используется литера :, поскольку апостроф ' встречается в тексте заголовка. Если перед запросом стоит знак ', а не ., то перед его выпол- нением вывод частично сформированной строки не производится. Запрос 'sp 2 в других отношениях идентичен запросу .sp 2 и пропускает 2 строки. Когда используется литера ., nroff вы- полняет разрыв печати строки так же, как и по запросу .Ьг, а использование литеры ' приводит к переносу частично сфор- мированной строки на следующую страницу. Прерывание печати строки происходит, когда входная строка начинается с пробела или является пустой строкой, или когда встречается один из следующих запросов: .bp .br .се .fi .nf .sp .in .ti
204 Гл. 7. Подготовка документов Вместо 'tl может использоваться .tl, поскольку запрос Л1 не вызывает перехода на следующую строку (хотя использова- ние ' дает тот же результат). Если в колонтитуле встречается специальная литера %, она заменяется на номер текущей страницы в десятичном виде. Запрос .af позволяет изменить формат, по которому печатается номер страницы. Например, .af % i вызывает печать номера страницы малыми римскими цифрами: i, ii, iii и т. д. При написании макроопределений для ловушек следует со- блюдать осторожность, особенно когда в колонтитуле исполь- зуются шрифт другого типа или буквы другого размера. Это обсуждается ниже в разделе, посвященном среде выполнения. Сдвиги по горизонтали и вертикали Для сдвига по вертикали внутри строки служат функции \d, \u и \v. Сдвиг на половину строки вниз выполняет функция \d, а сдвиг на половину строки вверх — функция \и. Функ- ция \v обеспечивает произвольный сдвиг вниз, например: \v'li' или вверх, например: \v'—11' Сдвиг на полстроки используется для печати верхних и нижних индексов. Например, X\dl\u порождает Х1 Сдвиги вниз и вверх должны быть сбалансированы; в противном случае можно получить нежелательный результат. Аналогичным образом с помощью функции задается сдвиг по горизонтали. Например, символ для обозначе- ния встроенного документа в языке-оболочке << записывается как <\h'—.2m'< Для большей наглядности эти две литеры сдвигаются поближе друг к другу.
7.1. Форматоры текстов nroff и troff 205 Расстояние, на которое надо выполнить сдвиг, может зависеть от длины цепочки литер. Для определения этой длины предназ- начена функция \w. Например, \w'do' дает длину цепочки символов do в базисных единицах. Напри- мер, do\h'—\w'do'u'do выделяет слово do при выводе на печатающее устройство. Это' слово напечатается один раз, затем функция \h выполнит воз- врат на то же место, и слово напечатается еще раз. Внутри функции \w могут присутствовать изменения типа и размера шрифта, однако эти изменения не оказывают влияния на окру- жающий текст. Символ и после функции \w, строго говоря, не обязателен, поскольку результат этой функции выдается в ба-, зисных единицах. Тот же эффект двойной печати можно получить с помощью функции \к, которая помечает текущую горизонтальную по- зицию в строке и запоминает результат в некотором регистре. Например, \kxdo\h' | \п хи 'do также напечатает слово do дважды на одном месте. Функция \кх запоминает горизонтальную позицию в регистре х, а функция \h'|...' выполняет сдвиг в заданную абсолютную позицию по горизонтали. Вертикальную позицию на странице можно пометить с по- мощью запроса .mk. Вывод продолжается как обычно, а для возврата в ту же самую позицию по вертикали внутри страницы используется запрос .rt. Это полезно при выполнении . вывода в несколько колонок. Например, в результате обработки фрагмента .mk о е > t ! : п .rt .in +4 Номер страницы нечетный. Номер страницы четный. Использование troff. Использование nroff. .in —4
206 Гл. 7. Подготовка документов будут напечатаны две колонки: первая с текущим отступом, а вторая со сдвигом на 4 эм, как показано ниже. о Номер страницы нечетный. е Номер страницы четный. t Использование troff. п Использование nroff. Если высота колонок различна, следует принять меры для того, чтобы после вывода второй колонки вернуться в правильное место. Можно рисовать вертикальные и горизонтальные линии. Функция \1'1Г нарисует горизонтальную линию длиной в 1 дюйм (вот такую: _____________). Можно также задать литеру, которой будет нарисована строка. Например, функция \l'li.' нарисует Функция \L аналогична \1, однако рисует линии по вертикали. Например, \кх\1'Н'\Ь'2'\Г—li'\h'|\nx'\L'—2' нарисует прямоугольник шириной в 1 дюйм и высотой в 2 строки: Условное форматирование Запросы и текст могут обрабатываться условно в зависимости от выполнения некоторого условия. Можно задавать как арифмети- ческие сравнения, так и сравнения цепочек литер. Простейшая форма условного запроса имеет вид .if с любые-данные Если условие с истинно, любые-данные обрабатываются систе- мой; любые-данные могут представлять собой текст или другие запросы форматора nroff. Список условий, встроенных в систему nroff, приведен на рис. 7.2.
7.1. Форматоры текстов nroff и troff 207 Например, условные запросы .if е Л1 '%'" .if о Л1 "'%' для четных страниц помещают их номера слева, а для нечет- ных — справа. Для проверки других условий (например, первая страница документа) следует использовать регистровые перемен- ные, предусмотренные в форматоре nroff. Имя Условие О Номер текущей страницы нечет- ный. е Номер текущей страницы чет- ный. t п Форматор troff. Форматор nroff. Рис. 7.2 Условия, проверяемые системой nroff Имеется несколько других видов условий: .if N любые-данные Любые-данные обрабатываются, если значение N больше нуля. ЛС 'текст1'текст2' любые-данные Любые-данные обрабатываются, если обе цепочки литер одина- ковы. Для отрицания условия можно использовать операцию I. Таким образом, .if !N любые-данные обрабатывает любые-данные, если N^O. Имеется также условный запрос типа if-then-else: .ie с любые-данные1 .el любые-данные2 Если с истинно, то обрабатываются любые-данные^; в противном случае обрабатываются любые-данные2. Если требуется выполнить несколько запросов, их можно заключить в скобки \{ и \}, как показано на рис. 7.3.
208 Гл. 7. Подготовка документов .ie \\n(sw \{ .nr sw О .in О .Ьр .ns \} .el \{ . ПГ SW 1 .rt .in I3i \} Рис. 7.3 Пример использования условного запроса Текстовые регистры Любую часто используемую последовательность литер можно определить как цепочку. Так же как и макро, цепочки имеют имена, состоящие из одной или двух литер. Имена цепочек и мак- ро принадлежат одному и тому же множеству имен, поэтому, если определить цепочку с именем хх, она заменит макро с таким же именем. Запрос определения цепочки имеет вид .ds хх цепочка где цепочка начинается с первой литеры, отличной от пробела и табуляции, и заканчивается в конце строки. Начальная двой- ная кавычка в цепочке отбрасывается; это позволяет определять цепочки, начинающиеся с пробелов. Например, нижний индекс 1 можно было бы определить так: .ds si \dl\u где \d и \u — сдвиги на полстроки вниз и вверх соответствен- но. Цепочка si используется в последующем тексте: x\*(sl и порождает xl. Имя может состоять и из одной литеры. Например, в nroff можно смоделировать жирную точку с помощью функции \о, наложив на о литеру +: .ds b \о'+о' На цепочку b в тексте можно ссылаться так: \*Ь -
7.1. Форматоры текстов nroff и troff 209 В цепочку можно вставить функцию перемещения по гори- зонтали. Например, символ встроенного документа, использо- вавшийся в гл. 4, определяется как .ds НЕ <\h'—.2т'< и используется в тексте как \*(НЕ. Числовые регистры В форматоре nroff имеется ряд числовых регистров, предназна- ченных для хранения числовых значений. Можно присваивать значения регистрам, увеличивать и уменьшать эти значения и использовать их в тексте. Имена регистров состоят из одной или двух литер; обращение к регистру имеет вид \пх или \п(хх Эти имена не зависят от имен, которыми обозначаются макро и цепочки. Регистры можно использовать в арифметических вы- ражениях и непосредственно в тексте. Например, nroff хранит день, месяц и год (отсчитываемый от 1900 года) в регистрах dy, mo, yr Поэтому 24 января 1983 года строка 19\n(yr \n(mo \n(dy напечаталась бы так: 1983 1 24 По умолчанию значения числовых регистров представляются арабскими цифрами, как в рассмотренном примере. Запрос af используется для определения формата значений числовых ре- гистров- и имеет вид •af R f где R — имя регистра, a f — один из форматов, приведенных ниже. Если формат содержит п цифр, то соответствующее поле будет состоять по крайней мере из п цифр. В форматоре nroff не определена цепочка, содержащая назва- ние текущего месяца, однако такую цепочку можно определить следующим образом: .if \n(mo—0 .ds МО Январь •if 4 n(mo—1 .ds МО Февраль
210 Гл. 7. Подготовка документов Таблица 7.2 Формат Последовательность нумерации 1 0, 1, 2, 3, 4, 5, ... 001 000, 001, 002, 003, 004, 005, ... i 0, i, ii, iii, iv, v, ... I 0, I, II, III, IV, V, ... а 0, a, b, c, ..., z, aa, ab, ..., zz, aaa, ... А 0, А, В, C, ..., Z, AA, AB, ..., ZZ, AAA, ... Эти запросы определяют цепочку с именем МО, содержащую на- звание текущего месяца. Числовым регистрам значение присваивается с помощью за- проса .пг. Например, запрос .nr IN 2m присваивает значение 2m (в базисных единицах) регистру IN, а запрос .nr IN +2m увеличивает значение IN на 2 эм. Значения регистров можно увеличивать или уменьшать авто- матически, используя следующие формы записи: \п+х Прибавить т к х. \п+(хх Прибавить tn к хх. \п—х Вычесть т из х. \п—(хх Вычесть т из хх. Величина т, прибавляемая или вычитаемая из регистра, уста- навливается запросом .пг. Например, запрос .nr sn 0 1 присваивает sn значение 0, а т — значение 1. Такая форма записи полезна для автоматического увеличения номеров раз- делов. Некоторые запросы, например .ink, также присваивают зна- чения регистрам. Так, запрос .mk pl
7.1. Форматоры текстов nroff и troff 211 Таблица 7.3 Имя Значение Описание .Н 1 Доступная разрешающая способность по горизонтали (в базисных единицах). .V 1 Доступная разрешающая способность по вертикали (в базисных единицах). .с 2691 Количество считанных входных строк. .1 270 Текущий сдвиг границы .1 3361 Текущая длина строки. .п 3020 Длина текста в предшествующей выходной строке. .0 697 Текущее смещение страницы. •р 7953 Текущая длина страницы. .S 10 Текущий размер шрифта (в пунктах) .t 3527 Расстояние до следующей ловушки. .V 120 Текущий интервал между строками. заносит в pl текущую вертикальную позицию (в базисных еди- ницах). В данном случае регистру pl присваивается значение 3540. Для возврата в это место можно использовать запрос .sp: .sp |\n(plu где I указывает на абсолютную позицию внутри страницы. Зна- чение, занесенное в регистр запросом .mk, выражено в базисных единицах, и символ и гарантирует, что nroff обработает это зна- чение правильно. Подразумеваемыми единицами, используемыми в запросе .sp, являются интервалы между строками. Если бы и не было задано, это было бы эквивалентно запросу .sp 13540 требующему пропуск 3540 строк от начала страницы. (Числовые значения, приводимые в этом разделе, зависят от устройства вывода.)
212 Гл. 7, Подготовка документов Для надежности в арифметических выражениях следует всег- да использовать и. Например, запрос .sp li/2 эквивалентен запросу .sp 3u так как подразумеваемыми единицами здесь являются интервалы между строками, и 2 будет рассматриваться как 2 интервала. Для того чтобы разделить 1 дюйм пополам, запрос следует запи- сать в виде .sp li/2u что эквивалентно запросу .sp 361 и Приведенные в табл. 7.3. регистры устанавливаются самим фор- матором nroff и доступны только для чтения. Во второй колонке приводятся значения, установленные для этой страницы англий- ского оригинала книги при выводе на устройство APS. Следующие регистры устанавливаются форматором troff и мо- гут быть изменены пользователем. Как и в предыдущей таблице, во второй колонке приведены значения, установленные для этой страницы. Таблица 7.4 Имя Значение Описание % 159 Номер текущей страницы. dw 2 День недели (1-7). dy 24 День месяца (1-31). hp 457 Текущая позиция по горизонтали. In 0 Номер выходной строки. nl 4600 Текущая позиция по вертикали. mo 1 Месяц (1-12). yr 83 Две последние цифры года (00-99).
7.1. Форматоры текстов nroff и troff 213 Шрифты Если не принимать во внимание разрешающую способность уст- ройства, то все рассмотренные до сих пор запросы были приме- нимы как к nroff, так и к troff. Современные фотонаборные уст- ройства предоставляют от 4 до 32 «штатных» шрифтов и ряд шриф- тов по требованию, а профессиональное печатающее устройство может иметь до 1000 различных способов вывода литер. В форматоре troff предполагается, что стандартными шриф- тами являются прямой светлый шрифт (гарнитура тайме), курсив и полужирный шрифт. Текущий шрифт можно сменить запросом •ft. Например, запрос •ft I вызывает печать текста курсивом, а .ft В изменяет шрифт на прямой полужирный. Такую смену шрифта можно выполнять и внутри строки при помощи функции Для того чтобы восстановить предыдущий шрифт, можно восполь- зоваться запросом .ft или .ft р Аналогично внутри строки конструкция \f(HIxx\fP вызовет печать хх гарнитурой гельветика курсив с последующим восстановлением предыдущего шрифта. Для восстановления прямого светлого шрифта используется запрос .ft R или функция ...\fR. Размер литер Размер литер (в том числе и литер, которыми набраны эти стро- ки) обычно равен 10 пунктам, где пункт равен 1/72 дюйма. Раз- мер литер можно увеличивать или уменьшать в зависимости от возможностей устройства вывода. Для этого предназначен за- прос .ps, а внутри текста используется функция \s. Например,
214 Гл. 7. Подготовка документов чтобы уменьшить размер литер в колонтитуле, можно воспользо- ваться конструкцией .tl '\s—2Руководство по системе UNIX\sO'... которая уменьшает размер шрифта на 2 пункта, а затем восста- навливает исходный размер. Чтобы сделать размер литер в на- званиях разделов равным 12 пунктам, макро SH можно было бы определить так: .de SH .ps 12 .ps Запрос .ps без параметра и функция \s0 восстанавливают пре- дыдущий размер литер. Макроопределение в таком виде может дать неожиданные результаты, если в параметре \$1 содержатся изменения раз- мера шрифта. Эту проблему можно обойти, сделав изменения размера шрифта относительными: .de SH .ps +2 .ps —2 Кроме того, если бы, например, размер литер в документе был изменен на 9, то размер заголовков разделов был бы все равно на 2 пункта больше. В этой книге расстояние между строками равно 120и (около 12 пунктов). Его можно было бы установить запросом .vs 12р Стандартный размер шрифта в книге равен 10 пунктам, а стан- дартный интервал между строками — 12р. Интервал между строками — это расстояние между соседними строками текста; он является подразумеваемым расстоянием, на которое выпол- няется вертикальный сдвиг по запросу .sp. При изменении размера литер интервал между строками не изменяется автоматически. По общему правилу интервал между строками должен быть примерно на двадцать процентов больше, чем текущий размер литер. Текущий размер литер доступен через регистр .s, а текущий интервал между строками — через регистр .v.
7.1. Форматоры текстов nroff и troff 215 Специальные литеры Специальные литеры, например греческие .буквы и некоторые математические символы, вводятся в систему troff в виде \(хх где хх — имя, состоящее из двух литер. Греческие буквы всегда записываются как \(*х где х представляет собой эквивалентную латинскую букву. Например, J Vu dr записывается как \(is \(gru d\(*t а а2 = k/p записывается как \(*a\u\s—22\s+2\d \(eq k\(sl\(*r Для такого рода приложений следует использовать препро- цессор eqn. Приведенные примеры иллюстрируют запросы фор- матора troff, предназначенные для порождения специальных ли- тер. Полный список специальных литер troff приведен в прило- жении 7. Авторегистровые последовательности Все литеры из набора ASCII, за исключением трех, приведенных ниже, выводятся в том же виде, как и вводятся. Некоторые специальные литеры и функции уже встречались и описываются здесь повторно; полный список специальных ли- тер и функций приведен в приложении 7. Таблица 7,5 Вводимая литера ASCII Вывод системы troff t > с 1 1 '
216 Гл. 7. Подготовка документов Таблица 7.6 Последова- тельность символов Действие \.е Печать литеры авторегистра. Печать знака острого ударения. Печать знака тупого ударения. — Печать знака минус. Хкх Сохранение текущей позиции по горизонтали в регистре х. Наложение друг на друга всех литер, заключенных в ка- вычки. Конец макроопределения. \& Отмена действия точки в начале строки. Начало комментария. //// Задание двойных кавычек в параметрах макровызова. Среда выполнения При переходе на следующую страницу для печати колонтитула может понадобиться сменить шрифт и размер литер. Обычно эти действия выполняются в ловушке конца страницы, где процесс заполнения строк приостанавливается для перехода на новую страницу. В форматоре nroff имеется механизм среды, который позволяет исключить влияние печати колонтитула на основной текст. Существует три среды выполнения. Каждая среда содер- жит независимые значения параметров, определяющих формат страницы, шрифт, размер литер, длину заголовка, режимы заполнения и частично обработанный текст. Запрос .ev п вы- полняет переключение на среду выполнения п, где п равно О, 1 или 2. Команда .ev без параметров восстанавливает предыдущую среду выполнения. Первоначально обработка начинается в сре- де 0. Например, для того чтобы изменить длину колонтитула и шрифт в макроопределении конца страницы РЕ, приведенном
7.1. Форматоры текстов nroff и troff 217 ранее, его можно переписать следующим образом: .de РЕ .ev 1 .It 4i .ps 12 .ft В 'sp 2 .tl руководство no UNIX :Г-я редакция 1971:Стр%: 'bp .ev Накопители и ловушки Текст, получаемый в процессе заполнения и выравнивания строк, обычно выводится. Однако текст примечаний необходимо хранить до конца страницы. Кроме того, размещение примечаний и длина основного текста зависят от размера накопленных примечаний. Накопители представляют собой механизм, позволяющий ре- шить проблему примечаний и другие аналогичные проблемы. Выводимый текст можно накапливать в макро с заданным именем. Таким образом можно собирать текст для примечания и определять его размер. Этот накопленный текст можно снова считать позднее, вызвав данное макроопределение. По запросу .di хх выводимый текст начинает накапливаться в макро с именем хх, замещая его прежнее содержимое. Накопление текста заканчи- вается, когда считывается запрос .di без параметров. Накоплен- ный текст можно ввести снова запросом .XX Вертикальный и горизонтальный размеры последнего накоп- ленного текста находятся в регистрах dn и dl соответственно. В форматоре nroff имеется три вида ловушек: страничные Ловушки, ловушки в накопителях и ловушки по количеству вход- ных строк. Страничные ловушки уже были описаны. Ловушки в накопителях устанавливаются запросом .dt и позволяют пре- рывать обработку при достижении заданной позиции по верти- кали в накопителе. Этот запрос используется аналогично запросу .wh. Например, .dt 1 DT
218 Гл. 7. Подготовка документов устанавливает ловушку в накопителе. Когда в текущий накопи- тель будет помещена одна выходная строка, выполнится запрос .DT. В каждый момент времени в накопителе может быть установ- лена только одна ловушка; следующий запрос .dt отменяет пре- дыдущую ловушку и устанавливает новую. Ловушка по количеству входных строк устанавливается за- просом .it; в нем указывается макро, которое следует вызвать после того, как будет считано некоторое количество входных строк. Данная ловушка выполняется только один раз. Напри- мер, по запросу .it 1 IT вызовется макроопределение IT после того, как будет считана (еще) одна входная строка. Используя этот механизм, запрос .ul для подчеркивания можно определить следующим образом: .de ul .it 1 UL .ft 1 .de UL .ft P 7.1.4. Макробиблиотека При подготовке документов целесообразно использовать макро- библиотеки. Имеются стандартные пакеты макроопределений, удовлетворяющие многим потребностям форматирования. Пакет макроопределений общего назначения позволяет выдавать до- кументы разнообразных форматов. Если в одном из этих пакетов нет требуемых средств, его иногда проще видоизменить, чем переписать, начиная с нуля. В этом разделе рассматриваются методы программирования, применяемые для создания пакетов макроопределений. Описанные здесь макроопределения исполь- зовались при подготовке английского оригинала текста этой книги; аналогичные средства предоставляются другими макро- библиотеками, например —ms. Последующее изложение имеет непосредственное отношение к приложению 9, содержащему полный листинг макробиблиотеки, использовавшейся при созда- нии английского оригинала этой книги. Краткая характеристика запросов, предоставляемых рас- сматриваемой здесь макробиблиотекой, дана в приведенной ниже таблице. Более подробное описание приводится в тексте. Форматор nroff терпимо относится к ошибкам: при обнаруже- нии ошибки обработка обычно продолжается без выдачи диагно- стического сообщения. Это усложняет процесс отладки. Чтобы
7.1. Форматоры текстов nroff и troff 219 Таблица 7.7 Запрос Описание .АН 1 "Команды" .CH 1 "Введение" .SH 1.1 "Историческая справка" .SS 6.3.1 "Полномочия файла" .MS "Использование амперсанда" Заголовок приложения. Заголовок главы. Заголовок раздела. Заголовок подраздела. Подзаголовок. .BU •IP (а) .LP .МР х++ .РР Абзац, выделенный жирной точкой. Сдвинутый вправо абзац с висячим текстом слева. Начало абзаца без отступа. Сдвинутый вправо абзац с висячим текстом программы. Начало обычного абзаца. .DS 13 .DE .ЕХ 24 .ХЕ .FX 34 .XF .FC 6.3 "Создание файла-замка" .FG lock, с 13 .RS .RE Начало иллюстрации. Конец иллюстрации. Начало примера. Конец примера. Начало рисунка в тексте. Конец рисунка в тексте. Подпись к рисунку. Включение файла, содержащего ри- сунок. Начало сдвинутого подраздела. Конец сдвинутого подраздела. .CN "1s" .DN "полномочия" .SN "новая строка" .HI "заголовок" .HL .RU Имя команды в тексте. Определение в тексте. Имя символа (литеры) в тексте. Шрифт, используемый для заголов- ков подразделов. Интервал в полстроки. Горизонтальная линия. .СХ парам! парам2 .IX парам! парам2 парамЗ Поместить в предметный указатель парам!, парам2 и парам2, парам!. Порождение элементов предметного указателя. избежать этих трудностей, описываемая здесь библиотека соз- давалась поэтапно. Сначала была написана и отлажена неболь- шая часть библиотеки и тем самым получен работающий костяк. Далее в эту «программу» (в данном случае набор макроопреде- лений для nroff) по одному вносились изменения. Поскольку ошибки, как правило, возникают в результате последнего вне- сенного в программу изменения, этот метод можно применять
220 Гл. 7. Подготовка документов при написании любых программ. Когда большая программа написана без тщательного тестирования всех ее частей, трудно понять, с чего начинать поиск ошибки. Начав с небольшого, но работающего варианта и постепенно развивая его, можно эф- фективно использовать ЭВМ в процессе построения программы. Первые макроопределения были написаны для абзацев и за- головков разделов. По мере необходимости добавлялись новые макроопределения; переделывались уже написанные макроопре- деления, если в них обнаруживались недостатки. В приведенных ниже примерах не всегда даются «окончательные» варианты мак- роопределений; показаны последовательные приближения, на- чиная с первого. Приложение . 9 содержит макроопределения в том виде, в каком они использовались для формирования английского оригинала этой книги. Для того чтобы избежать возможной путаницы с именами ба- зисных запросов nroff, имена макроопределений, как и в других макробиблиотеках, составлены из заглавных букв. Заголовки разделов Первый вариант макроопределения для порождения заголовков разделов показан на рис. 7.4. Обращение к этому макроопреде- лению имеет вид .SH номер заголовок Если заголовок содержит пробелы, его следует заключить в двой- ные кавычки. Номер раздела и его заголовок задаются отдель- ными параметрами, что позволяет подобрать подходящее расстоя- .de SH .sp 2 .ft В .in 0 \&\\$1 \\$2 .ft R .sp \” Заголовок раздела ’ . SH номер название \" пропуск пустых строк \" жирный шрифт ( игнорируется в nroff) \" переустановка сдвига границы \” параметры макроопределения \" восстановление стандартного шрифта Рис. 7.4 Первоначальный вариант макроопределения SH для формирования заголовков разделов ние между ними по горизонтали и изменять это расстояние, не меняя каждый макровызов. В последующих вариантах номер раздела был включен в колонтитул.
7.1. Форматоры текстов nroff и troff 221 Проверка на задание правильного количества параметров в этом макроопределении не производится. Строки, начинающиеся с . или и строки, содержащие \г обрабатываются форматором nroff при каждом их считывании. В макроопределениях это происходит один раз при обработке самого макроопределения и один раз при’ его вызове. Поэтому для обращения к параметру используется конструкция Комбинация \& в начале строки предотвращает интерпретацию начального символа . или ' в параметре при вызове макроопре- деления. Литера \ перед \$1 откладывает интерпретацию па- раметра до вызова макроопределения. Возврат к прямому светлому шрифту при помощи запроса .ft R вместо .ft Р защищает от возможной смены шрифта внутри заголовка, например: .SH 7.1 "\fHnroff\fP и \fHtroff\fP" Это также гарантирует переход на прямой светлый шрифт, даже если непосредственно перед новым разделом использовался ка- кой-либо другой шрифт. Впоследствии в SH были добавлены изменения размера шрифта и запрос, гарантирующий, что новый раздел начнется на данной странице только если на ней осталось по крайней мере 4 строки. Это позволяет избежать ситуации, когда название раз- дела попадает на одну страницу, а его текст — на следующую страницу. Добавления выглядят так: .пе 4 .ps +2 .ps —2 Заключительная правка SH состояла во введении регистра rs для управления левым полем страницы. Для участков текста с отступом левое поле меняется путем изменения значения регистра rs. Участок текста с отступом вво- дится макрозапросом RS (Relative Start). Чтобы запрос .RS можно было использовать вложенным образом, значение регистра rs увеличивается и уменьшается на некоторую величину. Макро- определение RS состоит из запроса .nr rs +2m который увеличивает значение регистра rs на 2 эм. Начальное значение присваивается rs запросом .nr rs О
222 Гл. 7. Подготовка документов в начале макробиблиотеки. Конец участка текста с отступом по- мечается запросом .RE. Проверка на соответствие запросов . RS и .RE не выполняется. Эта проверка может быть сделана отдель- ной программой, хотя ее можно встроить и в данные макроопре- деления следующим образом: .de RS .nr rs 4-2m .nr rc +1 \\n( '.de RE .ie \\n(rc \{ .nr rc —1 .nr rs —2m \) •el \{ .tm "Непарное RE" .nr rc 0 \) Регистр rc увеличивается на 1 при каждом обращении к RS и уменьшается на 1 при каждом обращении к RE. Если значение этого счетчика становится отрицательным, то при помощи за- проса Лт в файл диагностики выдается сообщение, а в регистр заносится 0. Заголовки глав Каждая глава этой книги хранится в отдельном файле и начи- нается следующим образом: .so maclib .CH 7 "Подготовка документов" По запросу .so считывается файл maclib, содержащий макробиб- ,de СН \н заголовок главы: .СН номер текст \\.ds cf \\$1 \\.ds ct \\$2 .се 2 \\$1 \\$2 .sp 8 Рис. 7.5 Первоначальный вариант макроопределения СН для формирования заголовков глав
7.1. Форматоры текстов nroff и troff 223 .de CH \” заголовок главы eCH 1 "Введение" .}Н "Глава \\$1" ’\\$2” .de АН \” заголовок приложения .АН 1 "Команды" .}Н "Приложение $ Г' ”\\$2И •de }Н \” макро для заголовков глав и приложений .sp 8 \\.ds cf \\$1 \\.ds ct \\$2 .ce 2 \\$1 .sp \\$2 .sp 3 Рис. 7.6 Макроопределения для формирования заголовков глав и приложений лиотеку, а затем возобновляется чтение файла, содержащего за- прос .so. Макрозапрос СН запоминает название и номер главы для последующего использования. Первоначальный вариант оп- ределения СН приведен на рис. 7.5. Название главы сохраняется в переменной ct, а номер главы — в переменной cf. Название главы используется в макроопределении для оформления начала страницы, а номер главы использовался (в предварительных вариантах) в тексте, помещавшемся в конце страниц. И номер, и название главы печатаются (с центрированием) в начале первой страницы главы. В последующие варианты этого макроопределения были вне- сены изменения, позволяющие формировать заголовки приложе- ний. Было введено третье макроопределение с именем }Н, как показано на рис. 7.6. Абзацы Для оформления абзацев сначала были написаны макроопреде- ления LP и РР; LP задает абзац без отступа (каким является дан- ный абзац), а РР — абзац с отступом в первой строке. Макроопределение для сдвинутого абзаца IP задает пол- ностью сдвинутый вправо абзац, слева от которого в первой строке помещается некоторый текст. Для получения абзацев подобного типа служат также макроопределения МР и BU.
224 Гл. 7, Подготовка документов Макро МР выводит висячий текст тем же шрифтом, которым выводятся тексты программ, а макро BU в качестве висячего текста использует жирную точку •. Написать эти три определе- ния оказалось сложнее, чем макроопределения для заголовков .de IP V сдвинутый абзац; .if n .sp .if t .sp .5 • ne 3 • in 6 • ta 4 .ti -4 \&\\$l\t\c \.if \^\*\\$1\'и-4т .br • IP (a) Рис. 7.7 Макроопределение IP — абзац с отступом разделов и глав. Типичным является макроопределение IP, первоначальный вариант которого приведен на рис. 7.7. Сдвиг для всех строк абзаца, кроме первой, обеспечивается запросом •in 6. Параметр макро IP обрабатывается строкой \&\\$l\t\c Метка сдвигается влево при помощи отрицательного временного отступа .ti —4. Для того чтобы достичь левого края текста, ис- пользуется табуляция (\t). Текст метки является параметром. В макроопределении ему предшествует \&, что позволяет предотвратить интерпретацию параметров как запросов в слу- чае, если они начинаются с точки. Комбинация\с блокирует переход на новую строку, так что текст может продолжаться на той же самой строке, несмотря на то что во входном файле при- сутствует литера новой строки. Если требуется, переход на новую строку выполняется в макроопределении запросом .if \w'\$ru-—4m .br (один уровень литер \ был удален при сканировании макроопре- деления системой nroff). Запрос в этом виде будет выполнен при вызове макро. Условие удовлетворяется, если ширина параметра $1 больше 4 эм. Буква и за \w'...z гарантирует использование правильных единиц измерения расстояния; строго говоря, она не является необходимой, так как \w возвращает длину в ба- зисных единицах.
7.1. Форматоры текстов nroff и troff 225 Оформление страниц В начале и в конце каждой страницы содержится текст, который выводится двумя специальными макроопределениями. Запрос .wh 0 аа информирует troff о том, что всякий раз, когда текущая позиция отстоит на 0 единиц от начала страницы, требуется выполнить макрозапрос аа. Макроопределение аа приведено на рис. 7.8., .de аа .ev 1 .It 7i .tl '—"—' .II 4.65i .It 4.65i 'sp 6 .ps 8 .ft R .tl '%\h'2m' Система UNIX "\\*(ct\h'2m’%' 'sp •ev Рис. 7.8 Макроопределение для оформления начала страницы Чтобы исключить влияние на основной текст, запрос в первой строке выполняет переключение на новую среду. Запросы в двух последующих строках порождают пометки для разрезания стра- ниц при выводе на рулонную бумагу. Так как длина заголовка отлична от ширины бумаги, эта длина устанавливается сначала равной 7 дюймам, а затем восстанавливается до нормальной величины. Первоначально номера страниц в колонтитулах выводились (при помощи специальной литеры %) и слева, и справа. В более поздних вариантах были введены два различных колонтитула страниц — левый и правый, печатаемые в зависимости от того, является ли номер страницы четным или нечетным. Для этого используются встроенные в nroff проверки на четность и нечет- ность номеров страниц, как в следующих двух примерах; .if е .tl '%\h' 2ш'Система UNIX"* .if о .« *"\\*(ct\h'2m'%' 8 С. Баурн
226 Гл. 7. Подготовка документов Конец страницы обрабатывается аналогичным образом. Вто- рая ловушка с именем zz устанавливается запросами .if n .wh —5 zz .if t .wh 9i zz В nroff эта ловушка ставится за 5 строк до конца страницы, а в troff — на расстоянии 9 дюймов от начала страницы. Внутри макроопределений, выполняемых ловушками, в за- просах, вызывающих переход на новую строку, используется ' вместо точки. Это блокирует вывод частично накопленной строки. Иллюстрации Иллюстрация — это фрагмент текста, который должен разме- щаться целиком на одной странице и в котором заполнение строк не требуется. Рисунки в этой книге представляют собой особый вид иллюстраций, начинающихся и заканчивающихся горизон- тальной прямой чертой. В макроопределениях для иллюстраций, описанных в этом разделе, пользователь сам должен задавать размер иллюстраций. Если иллюстрация не помещается на оставшейся части текущей страницы, эта часть остается незапол- ненной. Для оформления иллюстраций предоставляются два базисных макроопределения DS и DE, которые задают начало и конец иллюстрации. Определение DS выглядит примерно так: .de DS начало иллюстрации .DS 'in +2m .ta 4m 8m 12m 16m 20m 24m 28m 32m 'nf 'ne \\$1 Текст иллюстрации сдвигается немного вправо; устанавливается ряд подразумеваемых табуляций. Устанавливается режим без заполнения строк. Запрос .пе гарантирует, что будет зарезерви- ровано требуемое количество строк. Запрос DE задает конец иллюстрации. Он определяется как .de DE .HL .fi .in —2m Восстанавливается режим заполнения строк, и сдвиг края умень- шается на 2 эм. Запрос .HL генерирует сдвиг вниз на полстроки.
7.1. Форматоры текстов nroff и troff 227 Для оформления примеров программ используются запросы .ЕХ и .ХЕ, которые определяются следующим образом: .de EX .ft Н •fl .ss 20 .DS \\$1 .de XE .DE .ss 12 .ft R В этом примере были введены два новых запроса. Запрос .ss 20 устанавливает минимальное расстояние между словами равным 20/36 эм. Используемое по умолчанию минимальное расстояние 12/36 эм слишком мало для программ, набранных гельветикой. Интерпретация размеров литер является последним действием, выполняемым системой troff, когда выводимый текст копируется из внутренних буферов в выходной поток. Запрос .fl выталкивает текст из такого буфера. Этот запрос необходим здесь, чтобы пре- дотвратить влияние изменения размеров пробелов на еще не выведенный текст. Макроопределения .FX и .XF предназначены для оформления рисунков, в начале и конце которых помещается прямая гори- зонтальная черта. Каждое из этих макро определяется через базисные макро DS и DE. Последнее, на что следует обратить внимание в приложении 9,— это набор текстовых регистров. Эти регистры были введены для того, чтобы предоставить литеры, визуально более удобные, чем обычно используемые. Например, литера тильда обычно печатается как однако в программах требуется помещать ее на той же высоте, что и знак равенства = . Для красоты были выровнены также размеры литер. Создание предметного указателя Предметный указатель можно накапливать, вставляя в текст вызовы специального макроопределения, содержащие элементы предметного указателя. Это макроопределение, используя за- прос .tm, направляет элемент предметного указателя в файл диагностики. Если nroff вызывается командой troff глава 2>1х/глава 8*
228 Гл. 7. Подготовка документов то элементы предметного указателя будут накапливаться в файле ix/глава. Подоглавление используется для того, чтобы не засо- рять рабочее оглавление файлами, содержимое которых можно всегда сгенерировать заново. Макро IX для формирования элемента предметного указа- теля определяется следующим образом: .de IX \" элемент предметного указателя .if t .tm \\$1 \\$2 \\$3 \\$4 \\п% Для удобства было написано другое макроопределение СХ: .de СХ .IX "\\$1," " \\$2" .IX "\\$2," "\\$1" Используя СХ, одним запросом можно создать сразу два эле- мента в предметном указателе. Например, .СХ "макроопределение" \fHnroff\fP создаст два элемента предметного указателя: макроопределение, nroff\п % nroff, макроопределение\п% В вывод автоматически помещается номер страницы, содер- жащей запрос IX. Этот вывод обрабатывается потом с помощью командной процедуры index, приведенной в разд. 7.2. 7.2. ПОЛУЧЕНИЕ ИТОГОВОГО ДОКУМЕНТА По мере продвижения проекта разрабатываются новые команды и устанавливаются соглашения об именах файлов. Например, файл, содержащий предметный указатель для данной главы, хранится в подоглавлении с именем ix. Аналогично номера стра- ниц хранятся в другом оглавлении с именем page. Команды, описанные в этом разделе, создавались и дорабатывались в про- цессе написания данной книги. Эти команды выполняют: • Печать главы при помощи nroff и troff на различных устройствах вывода. • Генерацию номеров страниц. • Создание предметного указателя. Печать главы Команда печати главы имеет различные имена в зависимости от требуемого устройства вывода. Поскольку все варианты команды похожи друг на друга, удобно хранить их в одном командном
7,2, Получение итогового документа 229 файле. Это также упрощает процесс редактирования при добав- лении нового варианта команды. Команда вызывается по именам, перечисленным в альтернативах оператора case на рис. 7.9. t Используя troff, вывести текст на фотонаборном устрой- стве APS в виде, удобном для размножения. п Использовать nroff и выдать текст в стандартный файл вывода. Эта команда использовалась для просмотра тек- ста на простых устройствах вывода. args-'chapters' for i in ${*-$args} , do echo "$0 $$ $i ’date'11 >>log n«'cat page/$i' # для главы 7 использовать f bl и eqn case $i in t7) tbl $i I eqn ;; *) cat $i esac I case $0 in t) # Послать текст в вычислительный центр арз troff —n$n 2>ix/$i I aps n) # использовать nroff nroff —n$n 2>ix/$i •» p) # использовать proof troff -n$n 2>/dev/null I proof continue ix) # генерация предметного указателя troff -n$n 2>ix/$i >/dev/null esac makepage $i done Рис. 7.9 Печать глав
230 Гл. 7. Подготовка документов р Вывести текст на растровый дисплей с высокой разре- шающей способностью, используя специальный troff- инте^претатор. Так как этот вариант команды исполь- зуется интерактивно и ее выполнение часто прерывается до завершения вывода всего текста, предметный указатель не генерируется. ix Создать предметный указатель в файле ix/..., не выпол- няя вывода текста. Файл log содержит журнал работ. В него записываются имя команды $0, номер процесса $$, имя главы и дата. echo tp ТС t1 t2 t3 t4 t5 t6 t7 t8 echo А1 A2 АЗ a4 a5 a6 a7 a8 a9 a10 a11 tb TX Рис. 7.10 Имена файлов, содержащих тексты глав Номер страницы, с которой начинается глава, хранится в файле page/глава и присваивается переменной оболочки п коман- дой n='cat page/$i' Первоначально этот файл создается вручную. При вызове фор- матора troff номер страницы передается ему при помощи опции args-'chapters* for i in ${*-$args) do set — "'grep LAST <ix/$i' start='expr ${2-0} + Г if test —f page/next$i then next«'cat page/next$i' echo глава $next начиналась co страницы *cat page/$next' echo а теперь начинается co страницы Sstart echo $start >page/$next fi done Рис. 7.11 Процедура makepage —n. Номера страниц обновляются автоматически командой makepage, приведенной на рис. 7.11. Команда chapters, приведенная на рис. 7.10, представляет собой простую процедуру, использующую echo. В ней перечне-
7.2, Получение итогового документа 231 ляются главы в том порядке, в котором они будут следовать в итоговом документе. Некоторые главы порождаются автомати- чески путем обработки других файлов; чтобы отличить эти главы от остальных, их имена набраны прописными буквами. Нумерация страниц Главы печатаются раздельно, но нумерация страниц у них об- щая. Для каждой главы номер страницы, с которой она начина- ется, хранится в файле page/глава. Номера страниц обновля- ются командой makepage (рис. 7.11). • • \* задание действия по концу файла .ет ее V макро для обработки конца файла .de ее .af % 1 V установка прямого светлого шрифта Лт LAST \\п°/о. Рис. 7.12 Действие по концу файла При помощи макрозапроса .ет системы nroff (действие по концу файла) в предметный указатель вставляется ключевое слово LAST, как это показано на рис. 7.12. Процедура makepage использует это ключевое слово для определения номера послед- ней страницы данной главы. К этому номеру при помощи коман- ды ехрг прибавляется единица, и результат запоминается в файле page/..., соответствующем следующей главе. Команда set в процедуре makepage записывает номер стра- ницы, соответствующий ключевому слову LAST, в переменную оболочки $2. Переменной start присваивается номер страницы, с которой начнется следующая глава. Для каждой главы в оглавлении page содержится два файла. Первый из них содержит номер начальной страницы главы, а второй, с именем page/nexta^aea,— имя файла, содержащего текст следующей главы. Заключительная обработка предметного указателя Предметный указатель создается в файлах ix/... . Его нужно упорядочить по алфавиту и заново форматировать. Команда index обрабатывает элементы предметного указателя, полученные в результате работы troff, и создает итоговый предметный ука- затель в виде входного файла для troff. Если бы в предметном указателе применялся один шрифт, а размер литер оставался
232 Гл. 7. Подготовка документов неизменным, эта процедура была бы простой. В описанной ниже процедуре используется редактор sed. К каждой строке припи- сывается ее копия, а затем в левых частях строк удаляются за- просы изменения шрифта и размера литер. Результат сортиру- ется, после чего левые части отбрасываются. cat «! • so maclib ,)Н Index Ла 12m 14m 16m 18m 20m 22m 24m 26m .ps 8 .nf I args^'chapters’ see” for I in ${*-$args) do sed -e "s/ ♦// s /.♦/&—"--& I s/\\\\s-* \(.A)~~~~Al~~~~/g s/\\\\s-<\(.*\)~--/\1~---/g s / \\\\s. \(. *\)~— A1 ~— / g s/\\\\s.\(.»\)~—Д1-—/g s/\\\\f.\(.*\)-Д1-—/g s / \\\\f. \(. *\)-~—Д1 ~— / g s/\\\\f . ♦\)~'’~~/\l’~~~/g s/ / /g" <ix/$i done I sort -Lift' ' +0 -1 +1n I sed -e 's/. I xrefb Рис. 7.13 Постпроцессор index Команда cat в первой строке процедуры на рис. 7.13 генери- рует некоторый фиксированный набор запросов troff Для вклю- чения макробиблиотеки, установки табуляций, размера литер и режима без заполнения строк. Далее следует цикл по заданным параметрам — именам файлов. По умолчанию используется стандартный список имен. В первоначальном варианте предполагалось упорядочивать элементы предметного указателя непосредственно командой sort ix/*
7.3. Средства обработки текстовых документов 233 К сожалению, встречающиеся в элементах указателя запросы изменения шрифта и размера литер вызывают ошибки при сорти- ровке. В новом варианте команды (рис. 7.13) при помощи редактора sed создается файл с записями, состоящими из двух полей, разде- ленных некоторой легко распознаваемой цепочкой литер (в дан- ном примере цепочкой Первое поле содержит элемент указателя, в котором удалены запросы изменения шрифта и размера литер, а второе поле — элемент в первоначальном виде. Такой список создается в цикле for (рис. 7.13) и по конвейеру передается команде сортировки sort, причем ключом для сорти- ровки служит первое поле. Команда sort с опцией —uf исключает записи-дубликаты и при сортировке игнорирует различие между прописными и строчными буквами. Последний шаг заключается в использовании программы составления перекрестных ссылок, описанной в гл. 8. Эта про- грамма считываем строки вида элемент-указателя номер-страницы и порождает строки вида элемент-указателя номер-страницы! номер-страницы^ ... для элементов, на которые имеется несколько ссылок. 7.3. СРЕДСТВА ОБРАБОТКИ ТЕКСТОВЫХ ДОКУМЕНТОВ Средства, описанные до сих пор, позволяют создавать и форма- тировать текстовые документы. Имеются также средства для обнаружения орфографических ошибок, анализа стиля и предва- рительной обработки содержащихся в тексте таблиц и математиче- ских формул. col Преобразование вывода системы nroff с целью исклю- чить при печати перевод строк назад. diction Обнаружение плохо построенных фраз. eqn Подготовка математических формул. refer Оформление библиографических ссылок. spell Печать слов с сомнительным или неправильным на- писанием. style Сравнение внешних характеристик (ясность изложе- ния, структура предложений) каждой главы. tbl Подготовка табличных данных. Программы eqn, refer и tbl считывают текст из файла стан- дартного ввода и записывают переработанный текст в файл
234 Гл. 7. Подготовка документов стандартного вывода. Обрабатываются только участки входного текста, заключенные между парой определенных запросов; остальной текст копируется без изменений. 7.3.1. Команда со) Команда col считывает данные, полуденные в результате работы nroff и содержащие литеры перевода строки назад. Такие ли- теры порождаются, например, запросом .rt. Этот запрос гене- рируется препроцессором tbl и опциями печати в несколько коло- нок в некоторых макробиблиотеках. Команда col отфильтровы- вает эту и ряд других неграфических литер и порождает вывод, пригодный для простейших печатающих устройств. Обычный вывод системы nroff пригоден для телетайпа модели 37 (механического устройства, замечательного для своего вре- мени, но уже вышедшего из употребления). Вместо того чтобы использовать команду col, можно задать в команде nroff опцию, указывающую, что нужно сгенерировать вывод для простого терминала. Для терминала DASJ-450, например, эта опция за- дается так: nroff —Т450 ... 7.3.2. Команда diction Команда diction < доку мент находит в заданном тексте плохо или неправильно построенные предложения. В файл стандартного вывода записываются фразы, которые в обиходе часто употребляются неправильно. Хотя эти фразы могут использоваться преднамеренно, они все-таки отри- цательно влияют на восприятие документа. Как и в случае команды spell, можно сохранить в некотором файле те «ошибки», которые были допущены сознательно, и использовать команду comm или diff для распечатки «новых» ошибок. 7.3.3. Команда eqn Препроцессор eqn используется при подготовке математических формул для печати на фотонаборном устройстве. Родственная команда neqn выполняет те же функции для устройств типа пи- шущей машинки. Пользуясь eqn, можно печатать, например, знаки интегрирования, суммирования, извлечения квадратного корня, а также сложные выражения. Идеи, положенные в основу
7.3. Средства обработки текстовых документов 235 препроцессора, достаточно просты и понятны даже нематемати- кам. Участок текста, предназначенный для eqn, заключается между строками, начинающимися с .EQ и .EN. В простейшем примере .EQ х=а+Ь .EN будет выдано выделенное курсивом уравнение х=а+Ь Участок текста для eqn может быть также заключен между литерами-разделителями, определяемыми, например, так: .EQ delim $$ .EN . В этом случае текст Let $ 2 pi omega $ be the ... выводится в виде Let 2ло) be the ... Препроцессор eqn обрабатывает исходный текст, выдавая инструкции для nroff и troff. Прочие форматирующие действия (например, центрирование и выравнивание по левому краю) выполняются при помощи запросов nroff/troff, возможно, с ис- пользованием пакета макроопределений (например, —ms). Внутри eqn-запросов пробелы используются для разделения элементов; для вывода явных дополнительных пробелов исполь- зуется литера Входные данные имеют свободный формат и могут при необходимости занимать несколько строк. Элементы запросов можно группировать при помощи скобок { и }. Препроцессор eqn позволяет также набирать выражения с индексами, пределы, знаки частных производных, большие квадратные скобки для векторов и матриц, знаки суммирования (сигма) и длинные дробные выражения. Ряд примеров eqn-кон- струкций приведен в таблице, а ниже даются краткие пояснения. Нижние и верхние индексы генерируются при помощи ключе- вых слов sub и sup. Для получения дробей используется ключевое слово over, а для получения квадратного корня — sqrt. Ключевые слова from и to вводят любые нижние и верхние пределы. Левые и правые квадратные скобки подходящей высоты генерируются при помощи ключевых слов left и right. Правую скобку можно опускать. После слов left и right допускаются фигурные и квад- ратные скобки, вертикальная черта, символы с и f (округление
236 Гл. 7. Подготовка документов Текст для eqn Вывод troff х sub i Xi a sub i sup 2 aP- e sup {x sup 2 + у sup 2} a over b a T> x sup 2 over a sup 2 ‘ X2 ~aT sqrt {ax sup 2 +bx+c} у/ax2+bx+c lim from {n-> inf) sum from 0 to n x sub i lim Л“*ОО'ТГ left [ x sup 2 + у sup 2 over alpha right ] -=~1 -1 pile {a above b above c) % c matrix { Icol { x above у } cool { 1 above 2 } ) X 1 У ? x dot - f(t) bar x-f(t) у dotdot bar n under У=п x vec у dyad X -y до ближайшего целого с избытком или недостатком) и пустая комбинация "" (полезная, когда требуется только правая скобка). Элементы располагаются в столбец при помощи ключевых слов pile, Ipile, cpile и rpile. В столбце может содержаться про- извольное число элементов. Ключевое слово Ipile выравнивает столбец по левому краю, pile и cpile центрируют его, но с различ- ным интервалом по вертикали, a rpile выравнивает по правому краю. Матрицы формируются при помощи слова matrix. Кроме приведенных в таблице ключевых слов имеется еще ключевое слово rcol для выравнивания столбца по правому краю. Диакритические знаки формируются ключевыми словами dot (точка), dotdot (две точки), hat (шляпка), tilde (тильда), bar (черта сверху), vec (вектор), dyad (диада) и under (подчеркива- ние). Размер литер можно изменить, используя конструкцию size п или size ±п, а шрифт — при помощи спецификаций roman (пря- мой светлый), italic (курсив), bold (жирный) и font п (шрифт п). Размеры литер и шрифт можно изменить глобально во всем до- кументе, используя gsize п или gfont п, или же задав опции —sn и —fn в командной строке.
7.3. Средства обработки текстовых документов 237 Обычно размер нижних и верхних индексов уменьшается на 3 пункта по сравнению с размером литеры, к которой относятся эти индексы; эту величину можно изменить, задав опцию —рп в командной строке. Последовательные строки текста можно выравнивать по вертикали. Поместите mark перед желаемой позицией выравни- вания в первом уравнении; поместите lineup в позиции, которую требуется выровнять по вертикали, в последующих уравнениях. Процессор eqn распознает ключевые слова типа sum (2), int (J), inf (oo) и сокращения типа >= Q>), —> (->) и ! = (¥=)• В результате обработки текста .EQ t ~=~ 2 pi int sub 0 sup 1 sin ( sqrt { x sup 2 + a sup 2 } ) dx .EN будет получено уравнение t = 2л J sin(Kx2+a?)dx 0 Греческие буквы задаются их латинскими названиями в же- лаемом (верхнем или нижнем) регистре, например alpha и GAM- MA. Математические обозначения типа sin, cos, log автоматически выводятся прямым светлым шрифтом. В любом месте можно ис- пользовать принятый в troff четырехлитерный авторегистр, как в случае\(Ьз (@) . Цепочки литер, заключенные в двойные кавычки передаются без изменения; это позволяет вставлять в результирующий текст ключевые слова и передавать текст в troff в требуемом виде, если иначе это не удается. Если требуется подготовить и таблицы, и формулы, сначала следует использовать препроцессор tbl, например: tbl глава I eqn I troff —ms Для того чтобы включить библиографические ссылки, первой следует выполнить команду refer, так как и eqn, и tbl значительно увеличивают размер обрабатываемого текста. Например: refer статья I tbl I eqn I troff —ms 7.3.4. Команда ptx — порождение циклического указателя Циклический указатель, с которого начинается Руководство для программиста системы UNIX, был получен с помощью к команды ptx. Команда ptx <входной-текст >выходной-текст
238 Гл. 7. Подготовка документов создает циклический указатель из записей входного файла и помещает результат в выходной файл. Для указания файла клю- чевых слов используется опция —о файл-ключевых-слов Каждая строка входного файла циклически сдвигается таким образом, что ключевое слово попадает в начало строки. Файл, получившийся после выполнения всех операций такого рода, сортируется. Наконец, отсортированные строки циклически сдвигаются таким образом, чтобы ключевое слово попало в се- редину страницы. 7.3.5. Команда refer Команда refer ищет и форматирует библиографические ссылки. Она просматривает файл стандартного ввода в поисках ссылок вида .[ ссылка на литературу Ссылки на литературу задаются ключевыми словами. Например: ритчи томпсон система unix bstj 1978 .] Команда refer просматривает библиографическую базу данных и заменяет текст между .[ и .] набором определений цепочек в смысле nroff. При использовании пакета макроопределений —ms из этих цепочек печатается полная ссылка. Если задана опция —е, например refer —е статья то ссылки накапливаются и печатаются в том месте, где встре- чается $LIST$ .1 (обычно в конце документа). Предоставляется ряд опций для сортировки и нумерации ссылок. Стандартным файлом, содержащим библиографию, является /usr/dict/papers, но его можно заменить другим при помощи оп- ции —р. Команда refer печатает сообщения о неправильных или неоднозначных ссылках. Команда pubindex анализирует заданные файлы, содержащие требуемые библиографические ссылки, и создает для них эф-
7.3. Средства обработки текстовых документов 239 фективный индекс, который используется командой refer. Биб- лиографические ссылки в файлах отделяются друг от друга пустыми строками. Каждая ссылка состоит из нескольких строк, содержащих поля с библиографической информацией. Каждое поле начинается со строки, первой литерой которой является %; за этой литерой следует ключевая буква, пробел и далее — содер- жимое поля вплоть до следующей строки, начинающейся с лите- ры %. Наиболее часто используемыми ключевыми буквами и соответствующими полями являются: А Фамилия автора. В Название книги, содержащей данную статью. С Город. D Дата. d Дата (альтернативное поле). Е Редактор книги, содержащей данную статью. G Номер государственного заказа (CFSTI). I Издательство. J Журнал. К Прочие ключевые слова для поиска данной ссылки. М Номер технического документа. N Номер выпуска в пределах тома. О Комментарий, который следует напечатать в конце ссылки. Р Номера страниц. R Номер отчета. г Номер отчета (альтернативное поле). Т Название статьи, книги и т. п. V Номер тома. X Комментарий, не используемый командой pubindex. За исключением поля А, каждое поле должно задаваться не более одного раза. Следует задавать только существенные поля. Например: %Т 5-by-5 Palindromic Word Squares %А М. D. McIlroy % J Word Ways %V 9 %P 199-202 %D 1976 Родственная команда lookbib обеспечивает поиск библио- графии в интерактивном режиме. Например, команда lookbib unix bstj печатает все ссылки на статьи из журнала Bell System. Technical Journal, содержащие ключевое слово UNIX.
240 Гл, 7. Подготовка документов 7.3.6. Команда spell Команда spell проверяет написание слов из файла ввода по имею- щемуся у нее словарю. Обращение к ней имеет вид spell документ или spell —b документ Последняя форма проверяет английское правописание в проти- воположность американскому. Выводится список слов, не содержащихся в словаре. Этот список может содержать правильные слова, которые, однако, отсутствуют в стандартном словаре. Чтобы распечатать только новые орфографические ошибки, можно завести собственный файл необычных слов и воспользоваться командой comm, как это показано в следующем примере: for i do mv spell/$i spell/$i.prev <$i spell >spell/$i comm —23 spell/$i spell/$i.prev done Администратор системы (или лицо, имеющее доступ к файлу, содержащему словарь) может внести эти слова в стандартный словарь. Прежде чем начать проверку правописания слов по словарю, команда spell отсеивает запросы nroff/troff, используя фильтр deroff. 7.3.7. Команда style Команда style документ позволяет анализировать стиль (ясность изложения) документа. Печатается частота использования различных грамматических форм (в процентах). Сообщается уровень восприятия и инфор- мация о длине предложений, структуре предложений, длине слов, типе глаголов и способах построения фраз. Хотя эта инфор- мация является чисто структурной и поверхностной, она полезна при сравнении двух документов. Она может также указывать на чрезмерное употребление данной грамматической формы.
7.3. Средства обработки текстовых документов 241 7.3.8. Команда tbl Препроцессор tbl воспринимает простое описание таблицы и ге- нерирует запросы nroff для печати этой таблицы. Вводом для tbl служит текст документа вместе с информацией, описывающей таблицы. Запросы препроцессора tbl помещаются между .TS (начало таблицы) и .ТЕ (конец таблицы): .TS описание таблицы .ТЕ Весь остальной текст препроцессором tbl не изменяется. Сами строки .TS и .ТЕ также сохраняются в неизменном виде и могут использоваться в других макрозапросах. Описание таблиц имеет вид .TS опции, задающие внешний вид таблицы; формат столбцов и строк. табличные данные .ТЕ Литеры ; и . должны присутствовать явно, завершая соответ- ствующий раздел. Формат столбцов и строк в общем случае за- дается шаблоном, который по внешнему виду похож на саму таблицу. В следующем примере ф обозначает литеру табуляции, которая служит разделителем столбцов. .TS center; csss с с с с linn. Отделения фирмы Bell Labs Название ф Адрес ф Код ф Номер Холмдел ф -Холмдел, NJ 07733 ф 201 ф 949 Марри Хилл ф Марри Хилл, NJ 07974 ф 201 ф 582 Уиппени ф Уиппени, NJ 07981 ф 201 ф 386 Индиан Хилл ф Нейпирвиль, IL 60540 ф 312 ф 690 .ТЕ В результате получается таблица вида Таблица 7.8 Отделения фирмы Bell Labs Название Адрес Код Номер Холмдел Холмдел, NJ 07733 201 949 Марри Хилл Марри Хилл, NJ 07974 201 582 Уиппени Уиппени, NJ 07981 201 386 Индиан Хилл Нейпирвиль, IL 60540 312 690
242 Гл. 7, Подготовка документов В разделе описания форматов можно задавать следующие опции: с Элемент столбца центрируется. 1 Элемент выравнивается по левому краю столбца. п Числовая величина. г Элемент выравнивается по правому краю столбца. s Расширенный заголовок. Элемент из предыдущего столбца продолжается и в этом столбце. Опция center вызывает размещение таблицы посередине страницы. По умолчанию таблица располагается с левой стороны страницы. Внешний вид таблицы задается следующими опциями: allbox Поместить каждый элемент таблицы в прямо- угольную рамку. box Поместить всю таблицу в прямоугольную рамку. center Разместить таблицу посередине страницы (по умолчанию таблица располагается с левой стороны страницы). doublebox Поместить таблицу в двойную рамку. expand Разрядка. Использовать для размещения таб- лицы всю ширину страницы (текущую длину строки). tab(x) В качестве разделителя столбцов использо- вать литеру х вместо табуляции. Например, с использованием запроса allbox приведенная выше таблица будет выглядеть так: Таблица 7.9 Отделения фирмы Bell Labs Название Адрес Код Номер Холмдел Холмдел, NJ 07733 201 949 Марри Хилл Марри Хилл, NJ 07974 201 582 Уиппени . Уиппени, NJ 07981 201 386 Ин ди ан Хилл Нейпирвиль, IL 60540 312 690 Строка csss
7.3. Средства обработки текстовых документов 243 описывает поля в первой строке таблицы. Опция с означает, что поле должно центрироваться, a s указывает на то, что предше- ствующее поле должно быть продолжено и в этом столбце. Запрос с с с с задает формат второй строки. Эта строка состоит из четырех подзаголовков, размещаемых в середине столбцов. Формат остальных строк описывается как linn а . завершает раздел описания форматов. Буква 1 означает поле, выравниваемое по левому краю, ап — числовое поле, в котором выравнивание выполняется по младшей цифре.
ГЛАВА 8 СРЕДСТВА ОБРАБОТКИ ДАННЫХ Система UNIX хорошо известна своими средствами обработки данных. Среди них: awk Язык сопоставления с образцами и генератор отчетов, стр Сравнение двух файлов. сотт Выборка строк, общих для двух упорядоченных файлов. diff Выявление различий между двумя файлами. grep Сопоставление с образцом для группы файлов. join Объединение двух файлов путем соединения записей с одинаковыми ключами. sed Пакетный редактор (типа ed, но не интерактивный), sort Сортировка или построчное слияние файлов. tail Печать п последних строк входного файла. tr Преобразование литер. uniq Исключение из файлов последовательных строк-дуб- ликатов. В данной главе рассматриваются перечисленные выше средства и приводятся примеры их использования. Упор делается на по- строение новых средств из уже имеющихся. Объединение этих средств достигается при помощи оболочки, которая выполняет роль «клея». Программы на языке-оболочке легко читать и сопровождать. Если не приняты специальные меры, программирование на языке-оболочке с использованием команд как строительных блоков может оказаться неэффектив- ным. Однако работающую систему часто можно создать за более короткое время, чем если бы все программы были написаны на С. Если система оказалась удачной и требуется сделать ее более эффективной, то отдельные части этой уже работающей системы можно переписать. Далее в этой главе рассматриваются примеры, иллюстрирую- щие области приложений, в которых с успехом применяются перечисленные выше средства.
8.1. Краткое описание средств 245 Телефонный справочник В первом примере рассматривается организация работы со спис- ком телефонных номеров, имен абонентов и их адресов. Приво- дится программа для внесения в файл (список) новой информации. Номер можно получить по имени или по части имени абонента. Аналогично, по заданному номеру можно найти соответствую- щее ему имя абонента. В этом примере поиск в файле выполняется аналогично поиску в записной книжке. Программа для составления перекрестных ссылок В этом разделе показано, как можно объединить С-программу и программу, построенную с помощью lex, в одну систему, вы- дающую список перекрестных ссылок для С-программ. В этом списке для каждого идентификатора перечислены номера строк и файлы, в которых он встречается. Кроме того, для поддержки объектных модулей в корректном состоянии используется типич- ный make-файл. Сама программа построения перекрестных ссы- лок представляет собой командную процедуру, использующую две упомянутые выше программы. Одна из этих программ ис- пользуется также в гл. 7 в процедуре, формирующей предметный указатель для английского издания этой книги. Обработка результатов соревнований по теннису В этом примере описывается набор командных процедур для управления небольшой базой данных. Эта система ведет итоговую таблицу результатов встреч по теннису («табель»). Каждую неделю выводятся результаты и таблица модифицируется согласно некоторому набору пра- вил. В системе UNIX большинство из требуемых операций можно автоматизировать. Модификации таблицы выполняются каждую неделю в определенное время автоматически — никто не набирает команду непосредственно. 8.1. КРАТКОЕ ОПИСАНИЕ СРЕДСТВ В этом разделе кратко рассматриваются основные средства об- работки данных. Более подробные сведения, включая широкий набор имеющихся опций, можно найти в приложении 1 или полу- чить при помощи команды man. При обсуждении некоторых команд (например, join и sort) используется понятие полей записи. Запись — это строка текста. Поля внутри записей разделяются литерой — разделителем по- лей. Обычно в качестве разделителя полей используется литера
246 Гл. 8. Средства обработки данных табуляции. Это удобно, так как позволяет легко подготавливать итоговые документы с помощью системы nroff. Одни команды позволяют задавать разделитель полей, другие — нет. В некоторых случаях описываемые средства выполняют сход- ные функции. Например, в командах awk, ed, grep, lex и sed осуществляется отбор строк по некоторому регулярному выра- жению. В последующих примерах демонстрируются области применения, для которых эти средства наиболее подходят. Как правило, чем более узкую специализацию имеет средство, тем оно более эффективно для своей области применений. Например, команду wc следует использовать для подсчета числа строк, a grep или egrep — для выборки строк согласно некоторому об- разцу. Редактор sed используется, когда требуется преобразовать входной файл; пример этому — создание предметного указателя в разд. 7.2. Система awk обладает весьма большой общностью, но первое знакомство с ней может вызвать затруднения. Генератор программ lex требует понимания среды языка С. Регулярные выражения Термин «образец» используется в этой книге для обозначения набора цепочек литер. В зависимости от приложения этот набор задается различными способами. Например, в оболочке литера * сопоставляется с подцепочкой из нуля или более литер, а ? со- поставляется ровно с одной литерой* Оболочка предоставляет простейшие возможности сопоставления с образцами. В командах awk, ed, grep, lex и sed используются образцы, которые сопостав- ляются с входными цепочками. Для описания этих образцов иногда используется термин «регулярное выражение». Здесь приводится краткое описание регулярных выражений; более подробное описание можно найти в книге Ахо (1977). Регулярное выражение е определяется следующим образом (см. также описание образцов в редакторе ed — разд. 3.1.5). Термин «литера» в этом описании означает литеру, отличную от литеры новой строки. \с Обратная косая черта с последующей отличной от новой строки литерой сопоставляется с этой лите- рой. Л $ Литера л ($) сопоставляется с началом (концом) строки. . Сопоставляется с любой литерой. с Литера, не наделенная специальным значением, сопоставляется с такой же литерой. Цепочка литер, заключенная в квадратные скобки, сопоставляется с любой одной литерой из этой це-
8.1. Краткое описание средств 247 почки. Диапазоны литер, согласно кодировке ASCII, можно задавать сокращенно, например a—zO—-9. Скобка ] может быть только первой ли- терой цепочки. Собственно знак минус должен рас- полагаться в цепочке таким образом, чтобы его нельзя было спутать с указателем диапазона. е* Регулярное выражение, за которым следует лите- ра * (4-, ?), сопоставляется с последовательностью из 0 или более (1 или более, 0 или 1) вхождений этого регулярного выражения. el е2 При конкатенации двух регулярных выражений сопоставление производится с первым и следующим за ним вторым регулярным выражением. Описанные только что выражения можно использовать во всех программах, предоставляющих средства сопоставления с образ- цами, а именно в awk, ed, grep, lex и sed. Следующие регулярные выражения допускаются'только в awk, lex и egrep: el | е2 Если два регулярных выражения разделены лите- рой | или новой строкой, то сопоставление произ- водится либо с первым, либо со вторым регуляр- ным выражением. (...) Если регулярное выражение заключено в круглые скобки, то сопоставление производится с этим ре- гулярным выражением. Порядок выполнения операций на одном скобочном уровне следующий: [ ], *4-?, конкатенация, |. 8.1.1. Генератор отчетов awk Команда awk — это фильтр, в котором предусмотрены средства для обработки текста. Поведение awk полностью программирует- ся. Имеются условные операторы, циклы и переменные, причем форма записи аналогична форме записи в языке С. По команде awk программа файл! файл2 ... выполняются инструкции, заданные в цепочке программа; вход- ные данные берутся из указанных файлов. Если не задано ни одного файла, используется файл стандартного ввода. Вывод команды awk обычно поступает в файл стандартного вывода. Команда awk сканирует каждую входную строку в поисках селектора. Когда строка сопоставляется с селектором, выполня- ется связанное с этим селектором действие. Общая форма про-
248 Гл. 8. Средства обработки данных граммы такова: BEGIN{ начальные операторы } { селектор { действие } } END{ завершающие операторы } Может быть задано несколько пар селектор—действие. Считы- вается входная строка и по очереди вычисляются все селекторы. Если значение селектора истинно, выполняется связанное с ним действие. Селектор или действие могут отсутствовать. Если не задан селектор, действие выполняется для каждой входной строки, и если опущено действие, то входные строки копируются в выходной файл. Действие может состоять из нескольких операторов, разде- ленных точкой с запятой. Ключевые слова BEGIN и END вводят действия, которые выполняются один раз в начале и в конце файла соответственно. Команда awk считывает каждую входную строку, или за- пись, и разбивает ее на поля. Поля обычно разделяются пробе- лами или табуляциями. В выражении $0 обозначает всю теку- щую запись, а $1, $2, ... обозначают первое поле, второе поле и т. д. Число полей в текущей записи содержится в переменной NF, а число считанных входных записей — в переменной NR. Текущий разделитель входных полей и текущий разделитель входных записей хранятся в переменных FS и, RS. Подразуме- ваемым значением для FS является пробел или табуляция, а для RS — литера новой строки. Для обработки файла с полями, разделенными литерой : (таких, как /etc/passwd), в разделе BEGIN следует поместить оператор FS = Чтобы вернуться к подразумеваемым разделителям полей, пере- менной FS следует присвоить пустую цепочку литер. Раздели- тель выходных полей хранится в переменной OFS; по умолчанию, этим разделителем является пробел. Имя обрабатываемого файла хранится в переменной FILENAME. (Присваивание зна- чения этой переменной не изменяет источника ввода.) Примеры awk '/srb/' Распечатать все записи из файла стандартного ввода, содержащие цепочку srb.
8.1. Краткое описание средств 249 awk 'END{print NR}' Распечатать число входных строк. awk 'print $3' Распечатать третье поле каждой записи. Выражения Значением выражений являются, в зависимости от контекста, либо цепочки литер, либо числа. При необходимости awk пре- образует цепочки в числа. В выражениях можно использовать операции +, —, *, /, %, конкатенацию (задается пробелом), а также операции языка С: ++,-------, +=, —=, *=, /= и % = . Переменные могут быть скалярами, массивами элементов (обозначаемыми x[i]) или именами полей $1, $2, ... . Перемен- ные инициализируются пустой цепочкой. Операции отношения <, <=, = = ,! = , >= и > имеют тот же смысл, что и в язы- ке С. Аргументами этих операций могут быть как цепочки литер, так и числа. Например, выражение NF > 5 истинно для записей, состоящих более чем из 5 полей. Выражение $l>"s" истинно, если первое поле строки больше, чем цепочка "s", со- гласно лексикографическому порядку. Например, это выражение истинно, если первое поле содержит "st" или "tom". Выражение $2>=0 истинно, если второе поле содержит положительное число. Предусмотрены также явные операции сопоставления с образ- цом ~ и !~. Например, выражение $l~/srb|SRB/ истинно для записей, первое поле которых содержит цепочку srb или SRB, а $1~/[SsJtreet/ истинно тогда, когда первое поле сопоставляется с образцом [Ss]treet. Образцы, используемые в системе awk, описаны в разд. 8.1. Используя операцию запятая, можно ограничить действие диапазоном строк. Например, если задать /begin/,/end/ {...} то операторы в фигурных скобках будут применяться к участкам текста, начинающимся со строки, содержащей begin, и заканчи- вающимся строкой, содержащей end.
250 Гл, 8. Средства обработки данных Действия Действие в системе awk состоит из одного или нескольких опера- торов, разделенных точкой с запятой или литерой новой строки. Оператор может быть оператором присваивания, условным опе- ратором, оператором цикла или встроенной функцией (например, print). В целом синтаксис и набор операторов в awk такие же, как и в языке С. Операторы бывают следующего вида: if ( условие ) оператор [ else оператор ] while ( условие ) оператор for ( выражение ; условие ; выражение ) оператор for ( идентификатор in массив ) оператор break continue { [ оператор ] ... } переменная = выражение print [ список-выражений ] [ >выражение ] printf формат [ , список-выражений ] [ ^выражение ] next ф пропустить оставшиеся селекторы для этой вход- ной строки exit # пропустить остаток входного файла Операторы завершаются точкой с запятой, литерой новой строки или правой фигурной скобкой. Пустой список-выражений обозначает всю строку. Пример. Программа if ($2 > $1) { х = $1 $1 = $2 $2 = х } копирует файл стандартного ввода в файл стандартного вывода, меняя' местами $1 и $2, если значение $2 превышает значение $1. Сравнение является арифметическим, если это возможно, и лексикографическим в противном случае. Форматная печать Для форматной печати в awk имеются два оператора: print и printf. Оператор print без параметров выводит всю текущую запись. Оператор printf — более общий, чем print, и позволяет задавать любой формат, принятый в языке С (см. гл. 5).
8.1. Краткое описание средств 251 Например, программа i = 1 while (i <== NF) { printf "%s, ", $i i++ } печатает все поля, вставляя запятую после каждого поля. Опе- ратор print без параметров печатает всю текущую запись; зада- вая параметры, с его помощью можно распечатать отдельные поля, например: print $2, $1 Этот оператор печатает сначала второе поле, затем первое поле и завершает печатаемую строку литерой новой строки. Оператор printf не выводит никаких неявных разделителей — все разделители должны быть заданы в формате. Например, printf "%s, %s\n", $1, $2 распечатает два первых поля, разделив их запятой. Массивы в команде awk можно индексировать цепочками литер. Таким образом, имеется ассоциативная память. Приведем пример. Первое поле файла паролей содержит регистрационное имя пользователя. Следующая программа проверяет, что каждое регистрационное имя встречается только один раз. awk ' BEGIN{ FS=":" { if (user[$H) { print $1, "duplicated" user[$l] = NR }' </etc/passwd Все элементы ассоциативного массива доступны через оператор for. Например, for (i in user) оператор В этом примере выполняется цикл по всем индексам массива user. Стандартные функции Единственными функциями, доступными программисту, исполь- зующему awk, являются встроенные функции. Все они перечис- лены ниже.
252 Гл. 8. Средства обработки данных sqrt, log, exp, int Квадратный корень, логарифм по основанию е, экс- понента и целая часть. Параметр функции задается в скобках. length Длина параметра — цепочки литер. Если параметр не задан, возвращается длина всей текущей записи. substr(s,m,n) Выделить из цепочки s подцепочку, начинающуюся с m-й литеры (первая литера имеет номер 1) и со- держащую максимум п литер. index(s, t) Позиция первого вхождения подцепочки t в цепочку s. Первая литера имеет номер 1. Если t не является подцепочкой s, возвращается 0. 8.1.2. Команда стр—сравнение двух файлов Команда стр файлх файл2 сравнивает файл! и файл2. Если файлы идентичны, ничего не выводится; если же они не идентичны, стр выдает номер байта и номер строки, где встречается первое различие. Возвращаются следующие коды ответа: 0 Файлы идентичны. 1 Файлы различаются. 2 Файлы не доступны или не заданы параметры. 8.1.3. Команда comm — выделение общих строк Команда comm выделяет или исключает общие для двух упоря- доченных файлов строки. comm файл* файл2 Оба файла (файлх и файл2) должны быть упорядочены в лек- сикографическом порядке. Вывод выполняется в три колонки. Первая колонка состоит из строк, содержащихся только в пер- вом файле, вторая — из строк, содержащихся только во втором файле, а третья — из строк, общих для обоих файлов. Вывод некоторых из колонок можно отменить при помощи опции —[123]. Например, команда comm —23 f2
8.1. Краткое описание средств 253 отменяет вывод второй и третьей колонок и печатает только стро- ки, содержащиеся в первом файле, но не содержащиеся во вто- ром файле, в то время как команда comm —12 fj f2 печатает только строки, содержащиеся в обоих файлах. В качестве примера рассмотрим командную процедуру для обработки файла слов, отвергнутых командой spell. for i do z mv spell/$i spell/$i.prev <$i spell >spell/$i comm —23 spell/$i spell/$i.prev done При каждом выполнении процедуры предыдущее содержимое файла сохраняется, а сам этот файл обновляется. Команда comm печатает новые орфографические ошибки. 8.1.4. Команда diff — обнаружение различий в файлах Команда diff обнаруживает различия между двумя файлами. Она выводит из обоих файлов те строки, которыми эти файлы отличаются друг от друга, пытаясь минимизировать объем этих отличий. Вызов команды diff имеет вид diff файл] файл2 Вывод команды diff напоминает запросы а, с и d редактора ed. Перед строками из первого файла помещается литера <, а перёд строками второго файла — литера >. Если задана опция —е, порождаются запросы редактора ed для преобразования файлам в файл2. Например, команда diff —е fl f2 >diffs поместит в файл diffs запросы редактора ed, которые требуется выполнить для того, чтобы преобразовать файл fl в файл f2. Коды ответа команды diff: О Файлы одинаковые. 1 Файлы различаются. 2 Параметр-файл не задан или не доступен. В некоторых версиях системы UNIX команда diff с опцией —г рекурсивно просматривает два оглавления и выполняет команду diff для каждого файла в этих оглавлениях.
254 Гл. 8. Средства обработки данных 8.1.5. Команда grep — выборка по образцу Команда grep — это фильтр для сопоставления с образцом. Она уже рассматривалась в гл. 2. Команда grep образец файл ... выбирает из одного или нескольких файлов строки, соответствую- щие заданному регулярному выражению. Выражения, задающие образцы, описаны в разд. 8.1. Типичный случай использования команды grep — поиск име- ни переменной или функции в ряде файлов, содержащих исход- ные программы на языке С. Например, команда grep main *.с просматривает в текущем оглавлении все файлы, имена которых оканчиваются на .с, и печатает строки, содержащие цепочку main. Если просматривается несколько файлов, в начало каждой выходной строки помещается имя соответствующего файла. Если образец содержит литеры, имеющие специальное зна- чение для оболочки (например, * или Л), этот образец следует заключить в кавычки. Например: grep 'Al0—9][0—9]*' Коды ответа команды grep: О Ни одной подходящей строки не найдено. 1 Обнаружены строки, соответствующие образцу. 2 Файлы не доступны либо в регулярном выражении име- ются синтаксические ошибки. Код ответа команды grep можно использовать для проверки наличия в файле некоторой цепочки. В следующем примере if grep образец файл then ... fi в заданном файле ищется заданный образец. Если образец найден, выполняется часть then условного оператора. В команде grep не допускаются альтернативы в регулярном выражении. В команде egrep можно использовать регулярное выражение в общем виде, включающем операции | (альтернати- ва), + (одно или несколько вхождений),? (нуль или одно вхож- дение) и круглые скобки для подвыражений.
8.1. Краткое описание средств 255 8.1.6. Команда join — объединение файлов Эта команда объединяет два файла, соединяя записи с одинако- выми значениями ключей. Ключом является некоторое поле записи. Типичное обращение к команде join имеет вид join файлх файл2 где оба файла файлх и файл2 должны быть отсортированы в лек- сикографическом порядке по полям, по которым будет выпол- няться соединение. Подразумеваемым ключом является первое поле каждой строки. Для каждой пары строк из файлах и файла2, имеющих оди- наковое значение ключа, в выходной файл помещается одна строка. Обычно выходные строки имеют вид общее-поле остаток-строки-из-файлах остаток-строки-из-файла2 Предположим, например, что файл dept содержит строки вида имя ф отделение а файл cost содержит строки вида имя ф сумма ф дата-покупки Литера ф обозначает табуляцию. Предположим, что оба файла упорядочены по первому полю. Тогда команда join dept cost будет печатать строку вида имя отделение сумма дата-покупки для каждой пары строк из этих двух файлов, имеющих одинако- вые значения поля имя. Предположим, что файл dept содержит Leo 13 Shaw 12 а файл cost содержит Leo $35 3/82 Shaw $20 2/82 Shaw $45 4/82 Тогда выводом команды join dept cost будет Leo 13 $35 3/82 Shaw 12 $20 2/82 Shaw 12 $45 4/82
256 Гл. 8. Средства обработки данных Команда join имеет ряд разнообразных опций. Поля в вы- ходных строках в приведенном примере разделены пробелами. Если изменить литеру-разделитель полей при помощи опции —t'®', то поля как во входных, так и в выходных строках разде- ляются литерой табуляции. При помощи опции —о задается список выходных полей. Например, команда join —о 1.2 2.1 2.2 файлх файл, будет печатать второе поле из первого файла и поля 1 и 2 из второго файла (в указанном порядке). Для файлов dept и cost из рассматриваемого примера было бы получено 13 Leo $35 12 Shaw $20 12 Shaw $45 Поля, по которым будет выполняться соединение, можно за- дать при помощи опции —j. Параметр —jn m вызывает соединение по m-му полю n-го файла. Например, команда join —jl 2 —j2 2 файлх файл, выполняет соединение по второму полю обоих файлов. Наиболее частая проблема, возникающая при использовании команды join — не полный вывод. Это может произойти из-за неправильного задания опций, в которых важен пробел, или из-за того, что файлы не упорядочены по значениям соответ- ствующих полей. Следующую процедуру можно использовать для печати всех тех ключей из файла cost, которые не содержатся в файле dept. Как и прежде, ключ содержится в первом поле каждого файла. # распечатать имена из файла cost, не содержащиеся в файле * dept field 1 Ccost I sort —u >/temp/cost$$ field 1 <dept I sort —u >/temp/dept$$ comm —23 /tmp/cost$$ /tmp/dept$$ rm /tmp/cost$$ /tmp/dept$$ Команды в первых двух строках порождают упорядоченный список ключей из каждого файла (без дубликатов). Первая версия этой процедуры была написана без использо- вания опции —и в команде sort. Были получены неожиданные результаты, и потребовалось некоторое время, чтобы понять,
8.1. Краткое описание средств 257 в чем дело. Этого можно было бы избежать, если бы процедура строилась в два этапа. На первом этапе следовало бы получить временные файлы. Эти файлы можно было бы затем распечатать и проверить на непредвиденные обстоятельства (такие, как наличие строк-дубликатов). 8.1.7. Пакетный редактор sed Редактор sed используется как фильтр (не интерактивно). Функ- ционирование редактора sed во многом напоминает функциони- рование системы сопоставления с образцами awk, описанной выше. Считывается каждая строка входного файла и выполня- ются применимые к ней запросы. Запросы редактора sed анало- гичны запросам редактора ed. Последовательность глобальных подстановок эффективнее выполнять при помощи редактора sed, чем ed. Редактор sed вызывается командой sed —-е цепочка-запросов или sed —f файл-запросов Запросы из цепочки-запросов или файла-запросов применяются к файлу стандартного ввода. Чтобы избежать интерпретации литер программой-оболочкой, цепочку-запросов можно заключить в кавычки. В общем случае запрос имеет вид адресх,адрес2 запрос параметр Если адреса опущены, запрос применяется к каждой строке. Если оба адреса совпадают, можно задавать только один. Если задано два адреса, они ограничивают участок файла, к которому будет применяться запрос редактирования. Адреса могут за- даваться либо в абсолютном виде, как десятичные числа, либо контекстом. В последнем случае используются регулярные вы- ражения, заключенные между косыми чертами и аналогичные регулярным выражениям в редакторе ed. Операции и "—" при адресации строк не допускаются. В отличии от редактора ed запрос применяется к каждой строке, сопоставляющейся с адресом. Предусмотрены, в частности, следующие запросы: s/.../.../ Заменить подцепочку. d Исключить строку. а\ Добавить текст вслед за текущей строкой. i\ Вставить текст перед текущей строкой. с\ Заменить текущую строку. 9 С. Баурн
258 Гл. 8. Средства обработки данных Каждая строка текста, следующего за запросами a, i или с, кроме последней, завершается литерой\. Имеются также запросы для чтения файлов (г), записи в файлы (w) и печати (р). # печать полного имени команды, найденной в SPATH for j do for i in 'echo SPATH f sed —e 's/:/ /g” do if test -f $i/$j then echo $i/$j fi done done Рис. 8.1 Команда path Типичным примером использования редактора sed является команда path, приведенная на рис. 8.1. Во внешнем цикле пере- менной j присваиваются по очереди значения параметров коман- ды path. Во внутреннем цикле переменной i присваиваются по очереди все слова (цепочки, не содержащие пробелов) из вывода команды echo SPATH | sed — e's/:/ /g' Этот вывод состоит из списка имен оглавлений, взятых из пере- менной оболочки PATH. Имена в списке разделены пробелами. 8.1.8. Команда sort — сортировка и слияние файлов Если обращение к sort имеет вид sort файл! файл2 ... эта команда сортирует все строки из файлов файл!, файл2, ... и помещает результат в файл стандартного вывода. Если ни одного файла не задано, считывается файл стандартного ввода, поэтому команду sort можно использовать как фильтр. По умол- чанию ключом сортировки является вся строка; сравнение вы- полняется побайтно в соответствии с машинным упорядочением литер (обычно литеры представляются в коде ASCII). Этот по- рядок называется лексикографическим; примерно такой же порядок используется в словарях. Имеется опция для сортировки в числовом порядке. Запись вида + ПОЗх —поза
8.1. Краткое описание средств 259 ограничивает ключ сортировки цепочкой, начинающейся с пози- ции no3i и заканчивающейся непосредственно перед позицией поз2г Например, команда sort -J-0 —1 3 —4 сортирует сначала по первому полю, а затем (при равенстве первых полей) по четвертому полю. (Частой ошибкой при исполь- зовании команды sort является неправильное задание номеров полей.) Вслед за начальной позицией может следовать буква п, означающая, что сравнение для этого поля должно быть число- вым. Например, команда sort 4-0п ... задает сортировку по первому полю в числовом порядке. По умолчанию поля разделяются пробелами. При помощи опции —t можно .задать свою литеру-разделитель полей. Так, например, команда sort —t: ... выполняет сортировку по полям, разделенным двоеточием. Среди других полезных опций команды sort следующие: —п Сортировать по числовому значению поля. —г Изменить порядок сортировки на противополож- ный/ —и Выводить только одну из множества одинаковых строк. В командах sort и join используются различные способы ну- мерации полей внутри записи, и это может вызвать путаницу. В команде sort запись +0 —1 означает первое поле. В команде join первое поле задается как 1. 8.1.9. Команда tail — вывести последние строки файла Команда tail — фильтр, печатающий несколько последних строк файла. Опция —п, где п — число, указывает, что требуется вывести последние п строк файла. В некоторых версиях системы можно задавать опцию —г, которая вызывает печать файла строка за строкой в обратном порядке. Например, команда uulog, пе- чатающая журнал работ, выполненных системой пересылки файлов uucp, записывается так: tail —г /usr/spool/uucp/SYSLOG 9*
260 Гл. 8. Средства обработки данных 8.1.10. Команда tr — преобразование литер Команда tr цепочка1 цепочка2 преобразует и копирует в файл стандартного вывода литеры из файла стандартного ввода. Все литеры, заданные в цепочкеп преобразуются в соответствующие литеры из цепочки2. Если цепочка2 короче, чем цепочка^ она расширяется до размера цепочких посредством повторения последней литеры требуемое число раз. tr '[A-Z]' 'Ca-z]' Рис. 8.2 Команда lower Команда lower на рис. 8.2 преобразует все прописные буквы в строчные. Обратите внимание на то, что параметры заключены .в кавычки. Это позволяет избежать их интерпретации програм- мой-оболочкой как образцов для имен файлов. 8.1.11. Команда uniq — исключить повторяющиеся строки Эта команда читает упорядоченный файл и сравнивает соседние строки. Если обращение к команде имеет вид uniq файл то из файла исключаются вторая и последующие копии из каж- дого набора соседних повторяющихся строк и остаток выводится в файл стандартного вывода. Если файл не задан, читается файл стандартного ввода. Одинаковые строки обнаруживаются только в том случае, если они соседние; поэтому перед выполнением команды uniq может потребоваться выполнить команду sort. ЛЭпция —и команды sort выполняет то же действие, что и команда uniq, но в команде sort нет некоторых опций, имеющихся в uniq. Предоставляются следующие опции: —с Перед каждой строкой печатать, сколько раз она встре- чается в файле. —d Печатать только строки, имеющие дубликаты, и только по одной копии таких строк. Следующая программа порождает список слов из заданного множества файлов и выдает частоту использования каждого слова. Если ни одного параметра не задано, цикл for выполняется
8.1. Краткое описание средств 261 один раз, причем переменной i присваивается пустая цепочка, в результате чего команда tr будет читать файл стандартного ввода. for i in do <$i tr —cs A—Za—z '\012' done | sort —f | uniq —c 8.1.12. Команда field — выделение колонок Команда field является базисным средством, хотя и не входит в стандартные версии системы UNIX. Реализация этой команды приводится в разд. 8.4 как пример построения новых средств обработки данных. Параметрами команды field являются номера полей, которые нужно скопировать из каждой записи. Например, по команде field 2 4 3 читается файл стандартного ввода, и в файл стандартного вывода выдаются поля 2, 4 и 3, разделенные литерами табуляции. Ана- логичное действие выполняется посредством awk '{print $2, $4, $3}' но поля в выходном файле разделяются пробелами. 8.1.13. Генераторы программ lex и уасс В этом разделе кратко рассматриваются два средства построения компиляторов — lex и уасс. Система lex воспринимает набор регулярных выражении и связанных с ними действий — фраг- ментов программ на языке С. В результате порождается про- грамма, которая распознает в своем входном файле эти регуляр- ные выражения и выполняет соответствующие им действия. Эта программа используется в качестве лексического анализатора в компиляторах языков программирования, например языка С. Особенно удобно использовать lex в сочетании с уасс. Система уасс воспринимает на входе ЬАЬК(1)-грамматику вместе с фрагментами программ на языке С и генерирует про- грамму, выполняющую синтаксический разбор своего входного текста согласно этой грамматике. Каждый раз, когда распозна- ется некоторое правило, выполняется фрагмент программы пользователя, заданный для этого правила. Предполагается, что входной текст разбивается на лексемы лексическим анализато- ром, например анализатором, сгенерированным системой lex. Пример использования системы lex приводится в разд. 8.2.2.
262 Гл. 8. Средства обработки данных 8.2. ПРОСТЕЙШИЕ ПРИМЕРЫ 8.2.1. Сопровождение простой базы данных В этом разделе мы рассмотрим процесс разработки программы, которая добавляет новую информацию в файл, содержащий имена абонентов, их адреса и телефонные номера. Эта программа назы- вается enter; она приведена на рис. 8.3. date^'date' while prompt ’’name: “ read name do case $name in ") continue ;* q) break ;; esac prompt ’’address; “ address- while read a do case $a in ") # адрес кончается пустой строкой break ;; ♦) address-"$address~$a” ;; esac done prompt ’’phone: ” read phone 11 break echo "$name®$address®$phone®$date"»$HOh/IE/tel done Рис. 8.3 Команда enter Первоначальный набросок программы выглядит так: while read name * имя do read address ф адрес read phone ф номеР * добавить информацию в файл done
8.2. Простейшие примеры 263 Для чтения данных используется предоставляемая оболочкой команда read read v i v 2 которая считывает одну строку из файла стандартного ввода, разбивает ее на слова и записывает эти слова в переменные Vi, v 2» ... . Если слов больше, чем переменных, все оставшиеся слова присваиваются последней переменной. Команда read всегда возвращает код ответа 0, за исключением случая, когда достигнут конец файла. Если дополнить команду read командой break read phone || break то при неудачном завершении команды чтения будет происходить выход из цикла while. Причиной этого может быть, например, достижение конца файла при попытке прочитать данные или получение сигнала прерывания. Для того чтобы для обработки файла-справочника можно было использовать стандартные средства обработки данных, новая информация добавляется в этот файл в виде отдельной записи. В приведенном выше наброске предполагалось, что адрес состоит из одной строки. Ниже показано, как можно преобразо- вать адрес из нескольких строк в одну строку. Эта строка при- сваивается переменной оболочки address, а компоненты адреса, вводившиеся в виде отдельных строк, разделяются литерой ~. Ввод адреса завершается пустой строкой. address= while read а do case $a in ") break ;; *) address="$address~$a" ;; esac done Если оставить программу в таком виде, то при ее выполнении пользователь легко запутается, так как никаких приглашений для ввода он не получит. Кроме того, отсутствуют средства для исправления ошибок. Ввести приглашения не составляет труда; тем самым мы приходим к конечному варианту команды enter, приведенному на рис. 8.3. Для вывода приглашений используется команда prompt, состоящая из echo — п $* 1>&2
264 Гл. 8. Средства обработки данных Поиск телефонных номеров Для поиска имен абонентов или их телефонных номеров по спис- ку-справочнику идеально подходит команда grep. Эта команда используется в следующем описании процедуры tel: for i do grep "$i" <$HOME/tel done Здесь $HOME/tel — файл, содержащий исследуемые данные. Чтобы избежать интерпретации металитер программой-оболоч- кой, параметр команды grep заключен в кавычки. В файле-справочнике описанного здесь вида могут встре- титься сходные или даже идентичные записи, а некоторые записи могут устареть. Один из способов обнаружения возможных не- корректностей заключается в сортировке файла по различным полям. Строки-дубликаты можно удалить при помощи команды sort, например: sort —u <$HOME/tel >$HOME/newtel Получить список телефонных номеров, встречающихся в файле tel более одного раза, можно при помощи команды field 3 <tel | sort | uniq —d Опция —d задает вывод только записей, имеющих дубликаты (из группы одинаковых записей выводится только одна). Строки исходного файла, содержащие повторяющиеся телефонные но- мера, можно распечатать при помощи операции соединения (join) результата работы этой команды с исходным файлом tel. Эта процедура приведена на рис. 8.4. field 3 <tel 1 sort I uniq -d >/tmp/$$l sort -ГФ' <tel >/tmp/$$2 Join -ГФ' -И 1 -j2 3 /tmp/$$1 /Imp/$$2 rm /tmp/$$1 /tmp/$$2 Рис. 8.4 Печать повторяющихся телефонных номеров Соединяемые файлы должны быть упорядочены по полям, по которым выполняется соединение. Файл /tmp/$$l уже упоря- дочен нужным образом. Однако файл tel, вообще говоря, не является упорядоченным, поэтому вызывается команда сорти- ровки sort; ее вывод сохраняется в файле /tmp/$$2. Как в sort, так и в join требуется задать опцию —t'(D', ука- зывающую на то, что разделителем полей является литера табу-
8.2. Простейшие примеры 265 ляции. В данной процедуре эта литера заключена в одинарные кавычки, так как иначе она будет отброшена программой-обо- лочкой. В программу enter можно внести еще одно улучшение: орга- низовать проверку на то, что добавляемые телефонные номера еще не содержатся в файле-справочнике. Эта проверка имеет вид if grep "$phone" <$HOME/tel >/dev/null then ф номер уже есть . else ф такого номера еще нет fi Вывод команды grep (если он есть) направляется в пустой файл /dev/null. В этот файл может писать любой пользователь. Ли- теры, записываемые в него, «теряются». Для определения на- личия данного телефонного номера в справочнике используется код ответа команды grep. Следует сделать замечание об эффективности приведенных здесь процедур. Команда read встроена в оболочку, и поэтому ее использование достаточно эффективно. В некоторых версиях системы встроенными являются также команды echo и prompt. Команда grep не встроена в оболочку, и при каждом ее выпол- нении создается новый процесс. Эта операция является относи- тельно дорогой и может вызвать заметное ухудшение времени ответа команды enter. Насколько это серьезно, зависит от мест- ной операционной среды и размера файла-справочника tel. 8.2.2. Программа выдачи перекрестных ссылок В этом разделе описывается программа, порождающая список перекрестных ссылок для программ на языке С. Для каждого идентификатора выводятся имена файлов и номера строк в каж- дом файле, в которых встречается этот идентификатор. Для определений функций печатаются типы результатов. На рис. 8.5 приведен список перекрестных ссылок, полученный для файла xrefb.c (рис. 8.9). Программа построения списка перекрестных ссылок разбита на две части: xrefa и xrefb. Первая программа, xrefa, порождает список вида идентификатор ф имя-файла ф номер-строки Она реализована при помощи генератора программ lex; исход- ным файлом для lex является файл xrefa.I. Как показано на рис. 8.6, содержащем команду xref, вывод программы xrefa сор- тируется и подается на вход форматирующей программы xrefb. В результате получаются строки вида идентификаторфимя-файлафстроках строка, ...
266 Гл. 8. Средства обработки данных EOF xrefb.c 25 64 MAXW xrefb.c 5 6 13 65 argc xrefb.c 10 17 argv xrefb.c 11 с xrefb.c 61 64 66 69 cpstrO xrefb.c 3 36 40 43 f1 xrefb.c 13 22 32 40 41 f2 xrefb.c 13 23 34 36 43 44 first xrefb.c 14 27 28 getcharO xrefb.c 64 h xrefb.c 1 lastc xrefb.c 7 46 50 63 69 72 lastw xrefb.c 3 6 27 28 32 34 35 48 60 65 main(argc.argv) xrefb.c +9 n xrefb.c 46 63 64 P xrefb.c 60 65 66 71 printfO xrefb.c 18 29 35 41 44 48 52 stdio xrefb.c 1 strcmpO xrefb.c 32 34 strcpyQ xrefb.c 3 t xrefb.c 64 word() xrefb.c 25 33 42 47 word() / int xrefb.c +58 X xrefb.c 3 Рис. 8.5 Вывод команды xref для файла xrefb.c Программа xrefb написана на языке С, ее исходный текст хранится в файле xrefb.c. Команда xrefb использовалась также для обработки предметного указателя, составленного для ан-
8.2. Простейшие примеры 267 глийского издания данной книги (см. разд. 7.2). Программа xrefb читает трехколоночный вывод xrefa и переформатирует его, собирая в одной строке все ссылки на один и тот же идентифика- тор в одном и том же файле. xrefa $♦ I sort -ut: +0 +1 -2 +2n -3 I xrefb Рис. 8.6 Команда xref Файл для системы make На рис. 8.7 приведен make-файл для команды xref. Помимо записей для собственно программных файлов введены также записи для исключения промежуточных файлов (clean) и для xref: xrefa xreto xrefa: xrefa.о cc -o xrefa Xrefa.o -It xrefb: xrefb. о cc -o xrefb xrefb.о clean:; rm xref[ab].o install:; cp xref xrefa xrefb /usr/locaf/Ып .c.o:; cc -0 -c $< Рис. 8.7 make-файл для системы xref установки системы (install). Предполагается, что в оглавлении, содержащем исходные файлы, нет файлов с именами clean и install. Первый проход, xrefa В этом разделе кратко описывается lex-программа для первого прохода системы построения перекрестных ссылок. Полное опи- сание системы lex имеется В книге (Леек, 1975).
268 Гл. 8. Средства обработки данных Исходная программа для системы lex имеет вид % опции %{ определения %} % % описание-действий Раздел определения содержит определения в смысле языка С, в том числе определение функции main. Раздел описание-дей- ствий состоит из образцов, описанных в разд. 8.1, за которыми следуют собственно действия. Действие представляет собой опе- ратор языка С, который выполняется, когда входной текст сопо- ставляется с соответствующим образцом. Аналогичным образом работает система awk, за исключением того, что в случае lex входной файл не разбивается автоматически на записи. Кроме того, lex-программы компилируются. Опции lex В системе lex используется много внутренних таблиц. Раздел опции позволяет задавать размеры этих таблиц. Вывод команды lex xrefa. 1 имеет вид 372/500 nodes(%e), 3188/4000 positions(%p), 339/400 (%n), 21255 transitions, 54/100 packed char classes(%k), 967/1000 packed transitions(%a), 833/1000 output slots(%o) Указанные (в скобках) опции были установлены таким образом, чтобы в таблицах осталось достаточно свободного пространства. В остальном они интереса не представляют. В ряде случаев можно обойтись подразумеваемыми размерами таблиц. Сгенерированная системой lex программа помещается в файл lex.yy.c. Ее надо скомпилировать командой сс lex.yy.c —11
8.2. Простейшие примеры 269 Среда системы lex Система lex автоматически предоставляет стандартную библио- теку ввода-вывода. В данном примере она используется для от- крытия входных файлов. Система lex предоставляет и ряд дру- гих определений, в том числе: yylex( ) Вызов анализатора, построенного системой lex. Он будет читать текст из файла стандартного ввода. yyinput( ) Чтение одной литеры входного текста. yytextl 1 Цепочка, сопоставленная с текущим правилом. yyleng Длина цепочки yytext. yylineno Счетчик строк. Значение этой переменной уве- личивается на 1 при считывании каждой вход- ной строки. Подпрограмма main из раздела определений программы xrefa.1 обрабатывает параметры команды типичным для С-про- грамм образом. Действия вызываются в ходе выполнения функ- ции yylex. В данном примере при отсутствии параметров коман- ды вызывается функция yylex и читается файл стандартного ввода. Если параметры заданы, то при помощи функции freopen каждый файл открывается как стандартный ввод, запоминается имя этого файла и вызывается функция yylex. На рис. 8.8 приведены lex-правила для программы построе- ния перекрестных ссылок. В раздел НЕДОСТАТКИ странички руководства для пользователя по этой программе следовало бы поместить одно предостережение. Правило для распознавания определений функций не совсем корректно, так как тип резуль- тата может быть задан в строке, предшествующей имени функции. Ниже рассматриваются lex-правила из программы xrefa.1: "/*" Начало комментария. Вызывается функция comment, описа- ние которой имеет вид comment( ) { /* комментарии */ char с; while(c = yyinput( )) { if (с == '*' && yyinput() = = 'I') break; } } ®\"? Открывающая кавычка текстовой константы. Вызывается функция strings, описанная ниже; она пропускает литеры вплоть до закрывающей кавычки.
%к 100 %а 1000 %О 1000 %п 400 %е 500 %р 4000 %( char ♦filename-"-*; main(argc.argv) int argc; char *argv[]; { register int rc—0; if(argc<-1) { yylexO; }else( while(argc> 1) ( if(freopen(argv[1],"r",stdin)—NULL) { fprintf(stderr, "xref: %s: cannot open\n* argv[l] ): rc++; )else{ filename-argv[1]; yylineno-1; yylexO; ) argc—; argv++; 1 return(rc); } %} %% */♦" commentO; V stringsO; A[a—zA—ZJfa—zA—ZO—9 \tJ*"("fa-zA-Z0-9, ]»")"\n iff \t]*"(" ; returnf \t]»"(" ; whilef \t]»"(" ; for[ \t]«"(" ; switchf \t]*"C ; auto ; break fndef();
8.2, Простейшие примеры 271 Ia-zA-ZJ(a-zA-Z0-9J*[ { /♦ вызов функции */ printf("%s)\t%s\t%d\n", yytext, filename, yylineno); ) [a-zA-ZJ[a-zA-Z0-9J* { /♦ ссылка на идентификатор printf("%s\t%s\t%d\n", yytext, filename, yylineno); } • » \n ; Рис. 8.8 Исходный lex-файл для xrefa.1 strings( ) { /* строки */ char c; while(c = yyinput( )) { if(c == '") break; else if(c == '\\') yyinput( ); } л[а—zA—Z_][a—zA—ZO—9 \t_]*"("[a—zA—ZO—9, ]*")"\n Этот образец описывает идентификатор, стоящий в начале стро- ки, за которым следуют левая круглая скобка, последователь- ность идентификаторов и запятых, правая круглая скобка и литера новой строки. Предполагается, что таково определение функции. Это правило не совсем корректно, но пригодно для программ, имеющих стандартный формат, в частности для про- грамм, обработанных командой cb. Чтобы отменить в правилах специальное значение металитер системы lex (таких, как круг- лые скобки), их можно заключить в двойные кавычки. Для обработки определения функции вызывается С-функция fndef, приведенная ниже. Она просматривает распознанный по данно- му правилу текст в обратном направлении, выделяя конец иден- тификатора и тип результата, если этот тип задан. Тип резуль- тата печатается после имени функции и списка параметров. fndef( ) /» определения функций */ register char *р= &yytextlyyleng]; *----р = 0; /* удалить ) */
272 Гл. 8. Средства обработки данных while(*---р != '(')? while(*p—=' ' II *p= = '\t') { Р—; if(p<yytext) break; while(*p!=' ' && *p!='\t') { P—; if(p<yytext) break; p++; printf("°/os", p); if(p!=yytext) { *---p=0; printf(7%s", yytext); jLintf("\t%s\t+%d\rT, filename, yylineno—1); Остальные правила аналогичны уже описанным. После того как распознаны определения функций, считываются и игнориру- ются конструкции языка, содержащие круглые скобки. Оставшие- ся идентификаторы, за которыми следует левая круглая скобка, интерпретируются как вызовы функций. Ссылки на идентифи- каторы распознаются последними. Правила поглощают все оставшиеся литеры. Второй проход, xrefb Второй проход программы построения перекрестных ссылок воспринимает упорядоченный вывод от первого прохода и при- водит его к окончательному виду (рис. 8.9). В том виде, как она представлена здесь, эта программа может быть легко написана как awk-процедура. В первоначальном варианте этой программы имелся ряд опций для управления форматом вывода. 8.3. ОБРАБОТКА РЕЗУЛЬТАТОВ СОРЕВНОВАНИЙ ПО ТЕННИСУ В этом разделе мы рассмотрим использование всех средств сис- темы UNIX на примере законченной системы. В приводимых здесь программах наряду со стандартными командами системы используется команда field, описанная в разд. 8.4. Система ведет таблицу («табель»), содержащую текущие итоги соревнований по теннису между сотрудниками отделения фирмы Bell Laboratories в Марри Хилл. Табель представляет собой
8.3. Обработка результатов соревнований по теннису 273 файл, содержащий список игроков, упорядоченный в соответ- ствии с местами, которые они занимают в данный момент. Каж- дая строка этого файла состоит из следующих полей: • Идентификатор игрока (инициалы, если они однозначно идентифицируют игрока). • Место, занимаемое игроком. • Фамилия игрока. • Телефонный номер игрока. • Рабочее место (номер комнаты) игрока. • Число выигранных встреч. • _ Число проигранных встреч. • Перемещение игрока вверх или вниз по таблице за по- следнюю неделю. • Число недель, в течение которых игрок не принимал участия в играх. Система функционирует следующим образом. Результаты всех встреч, проведенных за период с понедельника по воскре- сенье, записываются в некоторый файл. Каждый вторник (по- недельник остается в резерве для ввода результатов встреч) табель модифицируется в соответствии с итогами встреч за прош- лую неделю. Если один теннисист побеждает другого теннисиста, занимавшего в табеле более высокое место, то победитель пере- мещается в табеле и занимает место непосредственно перед по- бежденным. В противном случае никаких перемещений не проис- ходит. Однако если игрок в течение трех или более недель подряд не провел ни одной встречи, каждую последующую неделю он опускается вниз на два места. Игрок, не принимавший участия в играх в течение семи недель подряд, исключается из табеля. 8.3.1. Организация системы Все связанные с рассматриваемой системой файлы хранятся в оглавлении $HOME/tennis или в некотором подоглавлении этого оглавления. В последующем описании это оглавление счи- тается текущим. Команды, поддерживающие и реализующие систему, хра- нятся в оглавлении ./bin (т. е. в оглавлении $HOME/tennis/bin). Такое отделение команд от файлов данных позволяет избежать чрезмерной загруженности основного оглавления и легко иден- тифицировать команды. Переменную PATH в оболочке удобно установить следующим образом: PATH=. ./bin :/usr/bin:. /bin: $HOME/bin Каждый год создается оглавление, которое используется как архив для хранения результатов. Оно применяется также для
274 Гл. 8. Средства обработки данных восстановления после сбоев. В большинстве описываемых ниже команд предполагается, что файл-табель существует и имеет имя .ladder. При тестировании системы имя этого файла храни- лось в переменной $ladder, которая была установлена и экспор- тирована из оболочки. В оставшихся подразделах этого раздела содержится описа- ние команд, реализующих различные компоненты системы обра- ботки результатов встреч по теннису: • Ввод результатов встреч. • Еженедельная модификация табеля. • Печать табеля. • Определение призеров. • Чистка файлов в конце сезона. Командные процедуры Для справок приведем сводку командных процедур системы. На рисунке отображена иерархия выполнения. Например, процедура стоп вызывает процедуру weekly, а процедура weekly вызываем процедуры run и send. стоп weekly run send update o«t I adr Г“ weed i I win setu-d 8.3.2. Ввод результатов встреч Информация о каждой игре состоит из даты, идентификаторов победителя и побежденного и счета встречи. Игроки идентифи- цируются при помощи своих инициалов. Если известна фамилия игрока, то можно получить и его идентификатор. И фамилии, и идентификаторы хранятся в файле-табеле. Программа для ввода результатов игр по своей структуре близка к программе из примера в разд. 8.2.1. Когда переменная $РАТН установлена соответствующим образом, программа record доступна из основного оглавления системы. Как показано на рис. 8.10, программа record выдает
©Include <stdlo.h> ©define MAXW 128 char lastwfMAXW); /♦ последнее прочитанное слово */ char lastc; main(argc.argv) int argc; char ♦argv[J; { char f1[MAXWl, f2[MAXW]; char first-0; /* args ? */ if(argc > 1) { printfCunexpected argument \n"); return(1); f1[0]-0; f2[0]-0; while(word() I- EOF)( if(lastw[O]!-first) f first-lastw[O]; printf("\n"); } if(strcmp(lastw, fl)--O) I wordO; if(!strcmp(lastw, f2) — 0) I printf("\n\t%s* lastw) strcpy(f2, lastw). } } else( strcpy(f1, lastw); printf("\n°/os", f 1); word(); strcpy(f2, lastw); printf(At%s", f2); ) if(lastc I- '\n'){ word(); printf('\t%s", lastw); lastc 0;
276 Гл. 8. Средства обработки данных printf(An">; return(O); ) /♦ ma/л */ I* прочитать слово из входного файла ь] /» результат сохраняется в lastw */ int word () { register char *p «• lastw; register int c; if(lastc I- V'){ while((c - getcharOJi-V && c!=\n' && cl-EOF) if(p < &lastw[MAXW]) { *p++ = c; } } lastc • c; } ♦p++ ~ 0; return(lastc); } /♦ word ♦ / Рис. 8.9 Исходная программа xrefb.c приглашения для ввода даты, победителя, побежденного и счета каждой сыгранной встречи: date: winner: loser: score: Если на приглашение date: дата введена правильно (напри- мер, 12/7), запрашиваются остальные поля. Конец файла или буква q вызывают выход из цикла и завершение процедуры. Кроме того, можно ввести имя игрока; в этом случае вызывается команда look (рис. 8.11), печатающая соответствующую строку из файла-табеля. Если введенное имя содержится в нескольких строках файла, look напечатает все эти строки. Далее читаются идентификаторы победителя и побежденного, проверяется, что эти идентификаторы имеются в табеле, и, нако- нец, запрашивается и считывается счет встречи. В ответ пользо- вателю выдаются полные имена участников встречи и занимае- мые ими места (согласно табелю). Пользователь должен под-
8.3. Обработка результатов соревнований по теннису 277 твердить правильность этой информации, и только тогда данные дозаписываются в файл .matches. Команды оболочки, выполняющие чтение и . проверку иден- тификаторов игроков, будут рассмотрены ниже, после описания процедуры readL. Процедура look Процедура look находит в файле-табеле все строки, содержащие заданные параметры. В простейшем случае, когда процедура NL-5’ # считать табель в LJd readL while true do prompt 'date: read D 11 break. case $D in 10-9]* *) # предполагается, что это дата ;? q) break ;; •) look $D 11 prompt T$D' not found$NL" continue esac prompt 'winner: read WP (I break # проверить, что игрок есть в табеле eval namew\-\$L_$WP case $namew in prompt "$WP not in the Iadder$NL* continue esac set $namew; rank1-$1; namet-$2j prompt 'loser: ' read LP II break eval namel\-\$L_$LP case $namel in ") prompt "$LP not in the ladder$NL*
278 Гл. 8. Средства обработки данных continue esac set $namel; rank2-$1; name2-$2; prompt "score: ' read S 11 break prompt "$nl$d $’namei($rank1) over $name2($rank2)" prompt *${NL)ok? • read ok case $ok ip у I ok I"). echo *$D Ф $WP Ф $LP Ф $S" ». matches *) prompt "result not recorded$NL" esac done Рис. 8.10 Процедура record look вызвана с одним параметром, $# имеет значение 1, и вы- полняется первая ветвь оператора case. Если задано более одного параметра, например look bob lucky выполняется последняя ветвь оператора case. Первый параметр записывается в переменную $а, и процедура look вызывается Case $# in 1) 0) ♦) esac tr (A-Z) [a-z] <.ladder J. grep "$Г ;; a-"$l"; shift; look "$♦" ] grep "Sa" Рис. 8.11 Процедура look снова co вторым параметром. Результаты второго вызова look пропускаются через фильтр ... I grep "$а" Таким образом, печатаются только строки, содержащие и bob, и lucky.
8.3. Обработка результатов соревнований по теннису 279 Процедура readL Некоторые аспекты процедуры record будут обсуждаться ниже, поскольку они опираются на реже используемые средства обо- лочки. Команда . readL на рис. 8.10 выполняет команды из файлов readL, как если бы этот файл был частью файла record. В результате выполнения readL (рис. 8.12) информация о всех игроках из табеля записы- # считать табель в L_id ехес 3<&0 <. ladder while read id rest do eval L_$id"'"$rest"' done exec 0<&3 3<&— Рис. 8.12 Процедура readL вается в переменные оболочки. Эти переменные затем исполь- зуются для проверки наличия записи об игроке в табеле. Тело процедуры readL состоит из цикла while while read id rest do eval L_$id="'$resf ' done причем входные данные считываются из файла .ladder. Если бы первыми строками файла-табеля были строки hga ... jmg ... то после выполнения readL переменным оболочки L_hga и L_jmg были бы присвоены значения: L_hga=... L_jmg=... Присваиваемым значением является строка из файла-табеля, соответствующая данному игроку. Такое использование eva! позволяет получить механизм, аналогичный массиву, не выходя за рамки языка-оболочки.
280 Гл. 8. Средства обработки данных Оператор read id rest читает очередную строку табеля и помещает первое ее слово (идентификатор) в переменную id, а остаток строки — в пере- менную rest. Если значением id является hga, то eval L_$id='"$rest"' интерпретируется оболочкой как L_hga="...- где ...— значение переменной rest. Оператор ехес в процедуре readL выполняет переадресацию стандартного файла ввода в оболочке, что позволяет в цикле while читать файл .ladder. Переадресация файла стандартного ввода в цикле while ... do ... done <.ladder не приведет к желаемому результату, так как при наличии пере- адресации «.ladder) в цикле while для его выполнения создается новый процесс. Этот новый процесс не сможет вернуть значения переменных оболочки своему родителю. Команда ехес 3<&0 дублирует дескриптор файла 0 при помощи системной функции dup. Сдублированный дескриптор будет иметь номер 3. Затем команда ехес <.ladder переадресовывает файл стандартного ввода. Эти две команды можно объединить в одну, как показано на рис. 8.12. Обратная операция выполняется после завершения цикла while при помо- щи команды ехес 0<&3 3<&— Проверка идентификаторов игроков Теперь, когда соответствующие переменные установлены процеду- рой readL, можно рассмотреть оставшиеся аспекты процедуры record, приведенной на рис. 8.10. *' После ввода идентификатора игрока-победителя проверяется, имеется ли запись об этом игроке в табеле.
8.3. Обработка результатов соревнований по теннису 281 Имена игроков берутся из переменных, установленных про- цедурой readL. При этом также используется eval. Команда eral namew\=\$L_$WP присваивает переменной namew значение переменной $L_..., где ... — значение $WP. Предположим, что выиграл игрок с идентификатором jmg. Тогда значением $WP будет jmg, и данная строка проинтерпретируется как namew=$L_ jmg При первом вычислении только $WP интерпретируется оболоч- кой. Команда eval передает полученную цепочку программе- оболочке для повторной интерпретации, в результате чего пере- менной namew присваивается значение, содержащееся в пере- менной $L_jmg. Если в табеле имеется запись об игроке jmg, переменной namew будет присвоено значение. В противном слу- чае печатается сообщение, и цикл возобновляется сначала. 8.3.3. Еженедельник действия Оставшуюся работу система обработки результатов соревнований по теннису выполняет в ранние утренние часы, когда многие машины слабо загружены и машинное время жалеть не прихо- дится. Такие работы планируются на определенное время в бу- дущем при помощи команды at. Команда at 0300 cron скопирует файл cron в системное оглавление (/usr/spool/at); копирование будет выполнено в 3 часа утра. Файл cron показан at озоо cron ехес »cron.i 2» cron. 2 set 'date' echo $♦ case $1 in Tue) Sun) esac wee J у ;; date >.Sunday Рис. 8.13 Процедура cron на рис. *8.13. Первая строка планирует выполнение этого файла на следующий день, а команда ехес >>сгоп.1 2>>сгоп.2
282 Гл: 8. Средства обработки данных переадресовывает файлы стандартного ввода и диагностики в не- которые файлы (иначе вывод будет потерян). Каждый вторник выполняется программа weekly, приведен- ная на рис. 8.14, а каждое воскресенье вывод команды date за- # модификация табеля по итогам встреч за неделю run # печать результатов за неделю send date >.Jastweek Рис. 8.14 Процедура weekly писывается в файл .Sunday. Выводимая этой командой дата ис- пользуется в программе печати табеля, которая будет описана ниже. set - 'date' year-$6 month-$2 day-$3 date-$month-$day # ожидание открытия замка trap ” 1 2 3 15 until mklock .lock do sleep 60; done echo $month $day weekly tennis run starting cp .ladder $year/${date)L cp .matches $year/$(date}G trap 'rm -f Jock; exit' 0 1 2 3 15 # модифицировать табель по итогам встреч за неделю update <.matches >.results # сохранить результаты для печати ср .results $year/$(date}R # очистить файл, содер жащий итоги встреч >. matches echo $month $day weekly tennis run ending Рис. 8.15 Процедура run
8.3. Обработка результатов соревнований по теннису 283 Процедура weekly модифицирует табель при помощи команды run (рис. 8.15). Для печати табеля (по одной копии табеля для каждого игрока) вызывается команда send. Напоследок дата печати записывается в файл .lastweek. Этот файл используется при печати для указания времени выдачи предыдущего табеля. Таким образом, участники игр могут проверить, все ли распечат- ки табеля ими получены. Команды модификации и печати табеля описываются в следующих двух разделах. 8.3.4. Преобразование табеля Мы рассмотрели организацию работы системы и планирование еженедельных и ежедневных действий. В этом разделе подробно рассматривается модификация табеля по итогам встреч за не- делю. Хотя описание ведется по методу «сверху вниз», на прак- тике при создании набора программ такого рода написание про- грамм верхних уровней, выполняющих организационные дей- ствия, можно отложить на последний этап. Процедура run Процедура run, приведенная на рис. 8.15, вызывается из про- цедуры организации еженедельных действий weekly. Она выпол- няет дальнейшие организационные действия и почти не требует пояснений. Команда mklock (разд. 6.4.1) гарантирует монопольный доступ к файлу .lock. Неудачное завершение этой команды озна- чает, что файл-замок не доступен; в противном случае осуще- ствляется захват замка. Этот замок можно использовать для того, чтобы предотвратить ввод результатов состоявшихся на неделе встреч в тот момент, когда выполняется процедура пре- образования табеля. Однако в представленной выше версии процедуры enter эта защита не реализована. Процедура update Процесс преобразования табеля разделен на управление файла- ми, выполняемое командой’ run, и на внесение изменений в соб- ственно файл-табель, выполняемое процедурой update (рис. 8.16). Как сам текущий табель, так и результаты встреч за неделю ко- пируются в архивное оглавление. Эти копии нужны для защиты от системных сбоев и программных ошибок. Кроме того, посколь- ку в процедуре win предполагается, что табель содержит записи о всех игроках, участвующих во встречах, снова проверяются идентификаторы игроков.
284 Гл. 8. Средства обработки данных После завершения преобразования табеля результаты сохра- няются в файле .results и в архивном оглавлении. Кроме того, лицо, контролирующее работу системы, уведомляется по почте о текущем состоянии табеля. В теле цикла while процедуры update для каждой проведенной встречи вызывается команда win. Каждая строка файла стандарт- ного ввода (обычно это файл .matches) считывается в перемен- ные D, WP, LP и S. Для установки переменных оболочки L_id снова используется процедура readL. Как и в процедуре record, NL~r г # считать табель в L Jd . readL # " обнулить поле "вверх •-вниз" setu-d # чтение записей о проведенных встречах while read D WP LP S do eval namew\-\$L_$WP case Snamew in ") prompt "winner \'$WP\' not known$NL‘ continue esac set $namew; rank1-$1; name1-$2; eval namel\-\$L_$LP case $namel in ") prompt "loser \'$LP\r not knownSNU” continue esac set $namel; rank2-$1; name2-$2; win $WP $LP # порождение записи для процедуры печати итогов echo ”$D Ф $name 1 (Srank i) Ф over Ф $name2($rank2) Ф $S" done # исключить неактивных игроков и оштрафовать # игроков, не игравших 3 недели weed Рис. 8.16 Процедура update
8.3, Обработка результатов соревнований по теннису 285 эти переменные используются для проверки наличия записей об игроках в табеле. В результате выполнения процедуры update создается список встреч, в котором для каждой встречи указаны фамилия игрока (вместо идентификатора) и место, которое за- нимал этот игрок на прошлой неделе. trap 'rm -f $tmp; exit' о I 2 3 15 tmp-'mktemp /tmp/tennisXXXXXX' awk <.ladder >$tmp " BEGIN { FS—,f ’ OFS—" " ) ( $8-0 print r trap ” 1 2 3 15 mv $tmp .ladder Рис. 8.17 Процедура setu—d Число в восьмом поле файла-табеля показывает, на сколько мест вверх или вниз по таблице переместился данный игрок за последнюю неделю. Программа setu—d (рис. 8.17) при помощи awk-процедуры обнуляет это поле. Процедура win записывает в это поле перемещения игроков вверх или вниз по табелю. Так как система awk — это фильтр, то для хранения промежуточных результатов требуется временный файл. Когда процедура setu—d завершает работу, она переименовывает этот временный файл в .ladder, воспользовавшись командой mv. Процедура win Запись о каждой проведенной встрече в файле .matches имеет вид дата ф победитель ф побежденный ф счет Победитель и побежденный задаются своими идентификаторами. Команда win (рис. 8.18) сканирует табель при помощи awk-про- цедуры. Она модифицирует второе поле (место, занимаемое игро-
# вызов процедуры: win победитель побежденный trap 'rm -f $tmpa; exit' 1 2 3 15 tmpa-'mktemp .tmpaXXXXX'- awk <$ladder ' BEGIN { FS-" ’ . OFS»" " W«0 L=O N=1 } { if($l —1'") { W - 1; $6 - $6 + 1; $9-----------------------1; if(LI-O) { $2 - L; N - NR; } 1 else if($1— "'$2'") { L - NR; $7 - $7 + 1; $9 - -1; if(W--O) { N - NR + 1;i $2 - N; } else { $2 - N; } J else { $2 - N; $8 - $8 + NR — $2; N - N + 1; print }' I sort +1n —2 >$tmpa trap " 1 2 3 15 mv $tmpa Sladder Рис. 8.18 Процедура win
8.3. Обработка результатов соревнований по теннису 287 ком), увеличивает счетчики числа побед и поражений и заносит —1 в поле, содержащее число недель, в течение которых данный игрок не принимал участия во встречах. Результат работы сис- темы awk упорядочивается по занимаемым теперь игроками мес- там. Наконец, модифицированный таким образом табель замещает старый. Первая проверка условия нуждается в пояснении. Первое вхождение $1 означает первое поле строки, считанной системой awk из файла стандартного ввода. Двойные кавычки интерпретируются системой awk; це- почка литер, заключенная в эти кавычки, передается оболочкой как первый параметр команды win (идентификатор победителя). Одиночная кавычка интерпретируется оболочкой и замыкает первую часть параметра awk: awk ' BEGIN{ ... ...'$1' Оболочкой интерпретируются awk и $1. Одиночная кавычка после $1 служит началом следующей заключенной в кавычки части параметра awk в смысле языка-оболочки. Само данное вхож- дение $1 находится вне одиночных кавычек, и поэтому перед выполнением команды awk оболочка подставляет вместо него параметр — идентификатор победителя. Если процедуру win вызвать посредством win hga jmg то параметр команды awk имел бы вид BEGIN{ } if($l =="hga") { (одиночные кавычки отброшены программой-оболочкой). В остальном команду win можно читать так, как будто это программа на языке С. Где надо, awk преобразует цепочки литер в числа. Тело awk-программы выполняется для каждой строки файла стандартного ввода. Значение присваивается переменной W в тот момент, когда при обработке файла-табеля встречается строка, содержащая идентификатор игрока-победителя. Значением переменной L
288 Гл. 8. Средства обработки данных становится место, которое занимал до этой встречи побежденный игрок. Различаются два случая: • Победитель занимал в табеле более высокое место, чем побежденный. Условие if($l = = "'$!'") будет выполнено и значением L будет нуль, так как за- пись о побежденном игроке еще не считана. Никаких перестановок в табеле делать не требуется. • Победитель занимал в табеле более низкое место, чем побежденный. При обработке записи о побежденном иг- роке значением W является нуль, и условие W==0 выполняется. Резервируется место для победителя (N=NR+1), а побежденный получает следующее после победителя место. Когда считывается запись о победи- теле, значение L уже установлено и равно месту, которое занимал до данной встречи побежденный игрок.. Условие L! =0 выполняется. Место, занимаемое до встречи по- бежденным игроком, отдается победителю ($2==L). Мес- та, занимаемые всеми оставшимися игроками, можно ос- тавить без изменения; в соответствии с этим переуста- навливается значение переменной (N=NR). Результат упорядочивается по занимаемым игроками местам и записывается во временный файл. Команда в последней строке делает этот временный файл табелем. Может показаться, что в состав рассматриваемой системы входит излишне много команд, каждая из которых выполняет только маленькую часть работы. Однако при таком построении системы можно тестировать отдельные части системы по мере их создания. Например, команду win можно вызвать непосред- ственно из оболочки, а входные данные для нее вводить с терми- нала. Аналогично, пока не реализован автоматический (при помощи команды at) запуск процедуры update, ее можно каждую неделю запускать вручную. Процедура weed Последняя программа, которая изменяет содержимое файла-та- беля, называется weed (рис. 8.19). Она обрабатывает записи об игроках, не проводивших встречи более трех недель. Такие игроки отодвигаются в табеле назад на два места, что стимули- рует активное участие в играх. Лидер освобождается от этого правила трех недель, поскольку ему не к лицу бросать вызов
8.3. Обработка результатов соревнований по теннису 289 другим игрокам. Игроки, не проведшие ни одной встречи в те- чение семи недель, исключаются из табеля. . Общий вид awk-процедур нам уже знаком. Значение поля, содержащего занимаемые игроками места, удваивается (R= =2*NR), а для проштрафившихся игроков дополнительно кор- ректируется (R= R+5). Затем табель сортируется по этому полю. Новые места вычисляются при помощи второй awk-процедуры. Корректируются также значения поля 8 (перемещения вверх- вниз по табелю). : Sftadder^ . ladder} trap 7m —f $tmp; exit' 0 1 2 3 15 tmp^'mktemp /tmp/tennisXXXXXX4 # исключить неактивных игроков и оштрафовать игроков, # не игравших 3 недели awk <$ladder ' BEGIN { OFS-"®" FS-"® ” } ( $9 • $9 + 1; $8 - $8 + $2; R - 2*NR; if($9 >- 3 && NRI-1) R - R + 5; if($9 < 7 II NR—1) { $2 - R; print } r I sort + 1n -2 I awk >$tmp * BEGIN { FS-"®* OFS-"®" } { $8 - $8 - NR; $2 - NR print }’ trap " 1 2 3 15 mv $tmp’ Sladder Рис. 8.19 Процедура weed 10 С. Баурн
290 Гл. 8. Средства обработки данных 8.3.5. Еженедельная печать табеля Итоговая таблица (табель) печатается каждую неделю. Каждому участнику адресуется своя копия, так что для рассылки табеля можно непосредственно воспользоваться внутриведомственной почтой. Печать организуется процедурой send (рис. 8.20). trap 'rm -f $out; exit' 0 1 2 3 15 out-'mktemp /tmp/otXXXXXX' # подготовить одну копию итогового документа* out .ladder >$out # разослать всем участникам while read line do adr $line <$out done <.ladder I Ipr Рис. 8.20 Процедура send Команда send вызывает программу out (рис. 8.21), которая подготавливает еженедельный итоговый документ. В качестве форматирующей программы используется nroff, причем стан- дартным вводом служит встроенный документ (после подстановок значений переменных оболочки). Длина страницы для заголовка устанавливается равной 6 вместо подразумеваемого значения 66 из-за того, что nroff заполняет остаток страницы пустыми стро- ками. Команда field выбирает все (разделенные пробелами) поля, кроме первого, а команда detab формирует текст в соответствии с позициями табуляции, заданными параметром. При помощи редактора sed в начало каждой строки вставляется литера табу- ляции, что позволяет выравнивать первое поле по правому краю, используя запрос ta системы nroff. Текст команды detab приведен на рис. 8.22. Если файл результатов (сгенерированный командой update) не пуст, он печатается. В заголовке указывается последняя воскресная дата. Перед печатью файл результатов форматируется согласно установкам позиций табуляции. Программа adr (рис. 8.23) разбивает итоговый документ (файл стандартного ввода) на страницы. Кроме того, к документу до- бавляется «шапка». Для оформления шапки используется функ- ция построения линий системы nroff. Значение, присваиваемое переменной оболочки banner, зависит от того, заданы позицион- ные параметры или нет. Значением является число пози- ционных параметров команды.
# печать табеля и результатов встреч у set 'date' year-$6 month-$2 day-$3 set — 'cat .lastweek' L_year-$6 L_month-$2 L_day-$3 # вывод заголовка nroff «! . nl 6 .11 80 .ce 2 • nf \” СИСТЕМА "ТЕННИС" .се 2 Состояние на $year$ month $ day ( Предыдущее сообщение $L_year $L_month$L_day ) место ф имя ф телефон ф комната ф победитель ф побежденный ф вверх-вниз Ф бездействие # вывод самого табеля field 23456789 <$ladder I sed —e 's/*/ Г I ta-"3R 5 32 42 56R 62R 68R 74C" detab set — 'cat .Sunday' S_year-$6 S_month-$2 S_day-$3 if test -s .results then # файл результатов не пуст nroff «| — .results .11 80 .pl 5 .sp 2 .ce Результаты встреч за неделю по SS jnonth SS_day .sp .tr _ .nf .ta 5 34 39 68 I fi Рис. 8.21 Процедура out 10*
(oat «I ; cat $♦) 1 nroff .pl 1 . nf .ta $ta 1 Рис. 8.22 Процедура detab case $# in 0) banner-'date' ;; *) banner-"$3 MH $5” ;; esac (cat «I; cat) I nroff .nf .tr _ .11 80 .wh 0 SP ,wh —4 EP .de EP .bp .de SP .sp 4 • • • SP • ce \i'\w'$banner,u+4\&-’ .in 70 $2 • in . ce Sbanner .sp .ce \l’\w'$banner* *u+4\&-/ .sp 3 I Рис. 8.23 Процедура adr
8.3. Обработка результатов соревнований по теннису 293 Для выделения почтового адреса используется функция по- строения линий системы nroff. Функция \r\w'$banner'u+4\&—' порождает прямую черту, отделяющую почтовый адрес ($banner). Функция \w'$banner'u вычисляет длину цепочки $banner в базисных единицах (и). Чтобы прямая черта выступала за пределы почтового адреса, к этой величине добавляется 4. Так как данная строка центри- руется, черта будет выступать на две литеры в каждую сторону. Функция и есть функция построения прямых линий; где ...— длина линии, вычисляемая при помощи предыдущего выражения. Функция & отделяет выражение, определяющее длину линии, от замыкаю- щего знака минус, который ъ противном случае считался бы частью выражения. 8.3.6. Начало и конец сезона Табель в первоначальном виде вводится в файл .initial. Каждый теннисист может запросить произвольное начальное место в та- беле. Эти вопросы по возможности будут учтены при упорядочи- вании исходного списка. Процедура startup (рис. 8.24) инициали- зирует все файлы, необходимые для работы системы. Следует также запустить файл cron. Определение призеров сезона Разыгрываются два приза: один для игрока, принявшего участие в наибольшем числе встреч, другой для игрока, выигравшего наибольшее число встреч. В обоих случаях учитываются только две встречи с одним и тем же противником. Для определения при- зеров предназначены две процедуры; они обе используют про- цедуру atmost, приведенную на рис. 8.25. Команда atmost вы- дает самое большее две одинаковые записи из вывода команды с именем, заданным параметром $1. Команда $1 должна порождать упорядоченный список. Она вызывается дважды. Сначала выполняется ${!?} | uniq —d
294 Гл. 8. Средства обработки данных ft создание файлов cat «I >.lastweek — — none ! >. results > .matches > .ladder sort +0n <. initial I awk BEGIN { FS-"®" OFS-"®" <N - 1; f - $i; $1 = $2; $2 = N; $6 - 0; $7 - 0; $8 - 0; $9 - 0; NF = 9; if(F !- (print; N-N+1;} >. ladder Рис. 8.24 Процедура startup в результате чего порождается список строк, встречающихся в выводе команды $1 по крайней мере два раза (по одной копии (${!?} I uniq -d ; $1 I sort -U) I sort Рис. 8.25 Процедура atmost от каждой группы одинаковых строк). Затем выполняется $1 I sort — U в результате чего порождается по одной копии всех различных строк. Конструкция (...)( sort
8.3. Обработка результатов соревнований по теннису 295 накапливает вывод первой команды, добавляет к нему вывод второй команды и сортирует результат. Игрок, выигравший наибольшее число встреч Игрок, выигравший наибольшее количество встреч, определяется командой most—wins, приведенной на рис. 8.26. Первая команда atmost list—matches порождает список пар игроков W L Каждая пара соответствует проведенной встрече между W и L, победителем в котором был W. Последующие команды в конвей- ере выделяют поле, содержащее имя победителя, и подсчитывают, atmost list-matches I field 1 I uniq -c I sdrt +Onr Рис. 8.26 Процедура most-wins сколько раз встречается одно и то же имя победителя. Так как atmost порождает упорядоченный вывод, первое поле можно передать непосредственно команде uniq. Опция —с порождает строки вида число фамилия-победителя где число указывает, сколько раз встречается данная фамилия- победителя во входном файле. Заключительное обращение к sort переупорядочивает список, помещая информацию об игроке, cd 1982; cat *G I field 2 3 I sort Рис. 8.27 Процедура list-matches одержавшем наибольшее число побед, в его начало. Параметр 4-0пг задает сортировку по числовому значению первого поля входного файла в порядке убывания. Процедура list—matches приведена на рис. 8.27.
296 Гл. 8. Средства обработки данных Игрок, принявший участие в наибольшем числе встреч Второй приз дается игроку, который провел наибольшее число встреч, причем учитывается не более двух встреч с одним и тем же противником. Команда list—players (рис. 8.28) порождает cat *G I field 2 3 i awk 'BEGIN I FS-*® OFS—"Ф ’ 1f($1 > $2) { t - $1; $1 - $2; $2 - t; 1 print I sort Рис. 8.28 Процедура list-players список встреч, причем фамилия первого игрока предшествует по алфавиту фамилии второго игрока. Таким образом, кто победил во встрече — значения не имеет, существенна только пара имен игроков. (atmost list—players I field 1; atmost list-players I field 2) I sort I uniq -с I sort +Onr Рис. 8.29 Процедура most-matches Команда atmost list—players порождает список встреч, сы- гранных всеми теннисистами, причем учитываются самое боль- шее две встречи между одними и теми же противниками. Первая строка процедуры most—matches (рис. 8.29) порождает список игроков-участников встреч; чтобы выполнить команду uniq —с, этот список надо сначала упорядочить.
8.4. Реализация команды field 297 8.4. РЕАЛИЗАЦИЯ КОМАНДЫ field Описание команды field в руководстве для пользователя имеет вид ИМЯ field — выделение полей (колонок) из файла РЕЗЮМЕ field [ п ] ... ОПИСАНИЕ Команда field копирует заданные поля из файла стандарт- ного ввода в файл стандартного вывода. Поля разде- ляются табуляциями и нумеруются, начиная с 1. Одно поле можно задавать несколько раз. НЕДОСТАТКИ Количество входных и выходных полей не может превы- шать 256. Максимальная длина строки — 4096 литер. Команда field выбирает заданные поля (разделенные табуляция- ми) из файла стандартного ввода. Результаты выводятся в файл стандартного вывода. На примере реализации команды field продемонстрируем не- сколько полезных приемов. Первый шаг состоит в поиске про- граммы, которая выполняет какое-нибудь аналогичное действие. Так как команда field представляет собой фильтр, копирующий данные из стандартного ввода в стандартный вывод, удобно взять за основу команду cat. Исходные тексты команд системы обычно хранятся в оглавлении /usr/src/cmd, поэтому легко можно использовать текст одной команды в качестве отправной точки при написании другой команды. Программа field приведена на рис. 8.30. Процесс написания этой программы состоял из следующих простых шагов: • Была написана программа, читающая строку в массив L и печатающая ее же снова (это команда cat с добавле- нием буферизации). • Добавлен код для запоминания границ полей и печати фиксированного поля. • Добавлен код для считывания параметров и печати за- данных полей. • Добавлены проверки на выход за границы массивов. Следующие опции опущены в программе, приведенной на рис. 8.30, но добавить их не составляет особого труда: — с Проверить, что все входные записи содержат оди- наковое количество полей. — tc Считать разделителем полей литеру с.
#include <stdio.h> #define MAXF 256 #define MAXL 4096 #define IFS V #define OFS At' int fv[MAXFJ; / * параметры в виде целых чисел ♦ / int nf; / ♦ количество колонок при печати * / int mf; / ♦ количество полей в текущей записи ♦ / char *fp[MAXF]; /♦ указатели на границы полей в 'L' ♦/ Char L[MAXL]; /♦ буфер текущей строки main(argc,argv) int argc; char *argv[]; register char ♦cp; register char ♦*ap; register int c; int f; /♦ считать параметры e fv[. ,,] ♦ / while (argc>1) { if(sscanf(argv[ 1 ], "%d”, &fv[nf++)) !« 1) { printfCusage: field [ n ] .. ,\n”); return(2); argc—; argv++; } /♦ чтение и копирование входного файла ♦ / nf—; ср = L; ар - fp; *ар++ - ср; while( 1){ с ~ getc(stdin); if(c=='\n' II c==EOF) ( int fc; if(cp«s= l && c==EOF) break; ♦cp++ — 0; mf *= ap-fp; /* печать данной строки ♦ / for(fc =a' 0; fc <** nf; fc-F-F) { putf(fv[fc]-1); if(fc != nf) putchar(OFS);
8.4. Реализация команды Held 299 } if(c — EOF) break; putchar(An'); cp e L; ap - fp; *ap++ — cp; else lf(c — IF$) { *cp++ «- 0; »ap++ cp; else *cp++ « c; return(O); } •/* вывести поле n текущей строки ♦/ O-Mtf(n) register char ♦cp « fp[nj; register char c; if(n<0 II n>*mf) return; while (c * *cp++) putchar(c); Рис. 8.30 Команда field В версии программы field, приведенной на рис. 8.30, не про- веряется выход за пределы границ массивов. Кроме того, гра- ницы массивов fv, fp и L фиксируются во время компиляции при помощи определений констант MAXF и MAXL. Программа, предназначенная для широкого использования, должна контро- лировать выход за эти границы или, еще лучше, отводить память под массивы динамически. Количество выходных полей можно определить по числу параметров. Количество входных полей и максимальную длину строки определить трудно. Другой вариант решения проблемы фиксированных границ в данной реализации команды заключается в предоставлении опций для изменения этих границ. Это оставляется читателю в качестве упражнения. Ограничения, присущие данной команде, были внесены в раз- дел НЕДОСТАТКИ соответствующей странички руководства для пользователя.
ПРИЛОЖЕНИЕ 1 КОМАНДЫ adb — отладчик ADB(l) adb [—w] [ объектный-файл [ core-файл ] ] Команда adb представляет собой отладчик общего назначе- ния. Его можно использовать для анализа содержимого файлов и для выполнения программ системы UNIX под управлением пользователя. Объектный-файл обычно является готовой программой. Же- лательно, чтобы он содержал таблицу символов. Без таблицы сим- волов нельзя использовать символьные средства отладчика, хотя все же можно анализировать содержимое файла. Подразумевае- мым объектным-файлом является a.out. Предполагается, что core-файл содержит образ памяти, полученный при выполнении данного объектного-файла. Подразумеваемым core-файлом яв- ляется файл core. Отладчик adb считывает запросы из файла стандартного ввода. Ответы записываются в файл стандартного вывода. Если задан флаг —w то объектный-файл и core-файл создаются (если это требуется) и открываются на чтение и запись, что позволяет мо- дифицировать их при помощи отладчика. Прерывание вызывает переход к считыванию следующего запроса, а сигнал выхода игнорируется. аг — система поддержки архивов и библиотек AR(1) аг ключ [ позиц-имя ] а-файл имя ... Команда аг обслуживает группы файлов, объединенных в один архивный файл. Главным назначением команды аг является создание и обновление библиотечных файлов, используемых за- грузчиком. Однако ее можно использовать и для любых других аналогичных целей.
Приложение 1. Команды 301 Ключ представляет собой одну литеру из набора drtpx, за которой может следовать одна или несколько литер из набора vuaibcl. Параметр а-файл задает имя архивного файла, а файлы, входящие в архивный файл, задаются параметрами имя. Литеры в ключе имеют следующий смысл: d Исключить указанные файлы из архивного файла. г Заменить указанные файлы в архивном файле. Если вместе с г.задана необязательная литера и, то заме- няются только файлы, имеющие более поздние даты модификации, чем файлы в архиве. Если используется необязательная литера из набора abi, указывающая позицию, то должен быть задан параметр позиц-имя. Новые файлы будут помещаться вслед за (а) или перед (Ь или i) файлом позиц-имя. В противном случае но- вые файлы помещаются в конец архива. t Распечатать оглавление архивного файла. Если не за- дано ни одного параметра имя, печатаются имена всех файлов в архиве. Если параметры имя заданы, печа- тается информация только об указанных файлах. р Распечатать указанные файлы из архива. х Извлечь из архива указанные файлы. Если не задано ни одного параметра имя, из архива извлекаются все файлы. В любом случае опция х не изменяет архив- ный файл. v Выдавать пояснительные сообщения. Если задана эта опция, аг дает подробное описание процесса создания нового архивного файла из старого архива и состав- ляющих файлов, выдавая сообщение о каждом обра- батываемом файле. Если эта опция используется совместно с t, то информация о файлах архива вы- дается в длинном формате. Если эта опция исполь- зуется вместе с р, то перед каждым файлом печатается его имя. с Создать архивный файл. Обычно команда аг при не- обходимости создает архивный файл а-файл; данная опция подавляет информационное сообщение, выда- ваемое при создании архивного файла. at — выполнить команды в заданное время АТ(1) at время [ день ] [ файл ] Команда at создает копию указанного файла (по умолчанию — файла стандартного ввода). Эта копия будет передана программе- оболочке sh(l) в качестве входных данных в заданный момент времени в будущем. В начало файла-копии вставляется запрос cd
302 Приложение 1. Команды на текущее оглавление, а вслед за ней — установки всех пере- менных среды (кроме переменной TERM, использование кото- рой в данном контексте лишено смысла). При выполнении про- цедуры устанавливаются идентификатор пользователя и иден- тификатор группы создателя файла-копии. Параметр время состоит из 1,2,3 или 4 цифр, за которыми может следовать одна из букв А, Р, N или М, обозначающая время суток (утро, вечер, ночь, день). Одна или две цифры задают часы, три или четыре — часы и минуты. Если за цифрами не следует буква, считается, что время задано по 24-часовой шкале. Необязательный параметр день представляет собой либо дату (название месяца и день месяца), либо день недели. Если далее следует слово week («неделя»), то время выполнения коман- ды сдвигается дополнительно еще на 7 дней. Можно использо- вать сокращенные названия месяцев и дней недели. awk — язык поиска и обработки по образцам AWK(l) awk [ прог ] [ файл ] ... Команда awk просматривает каждый входной файл в поисках строк, которые соответствуют какому-либо из образцов, задан- ных в программе прог. С каждым образцом в прог может быть связано действие, которое будет выполнено в случае, если строка файла соответствует данному образцу. Набор образцов может быть задан либо явно в параметре прог, либо в файле, задаваемом посредством —f файл. Файлы читаются в указанном порядке; если ни одного файла не задано, читается файл стандартного ввода. Знак минус в спис- ке имен файлов означает файл стандартного ввода. Команда awk описана в гл. 8. basename — выделить основу из имени файла BASENAME(l) basename цепочка [ суффикс ] Команда basename удаляет из цепочки префикс, оканчиваю- щийся литерой / (если таковая есть), и заданный суффикс. Ре- зультат записывается в файл стандартного вывода. cal — напечатать календарь CAL(l) cal [ месяц ] год Команда cal печатает календарь на указанный год. Если задан и месяц, то печатается календарь только на этот месяц.
Приложение 1. Команды 303 Год задается числом от 1 до 9999, месяц — числом от 1 до 12. Календарь выдается в виде, принятом в Англии и ее колониях. calendar — календарная служба напоминания CALENDAR(l) calendar 1 — ] Команда calendar просматривает файл calendar в текущем оглавлении и печатает из него те строки, в которых (в произволь- ном месте) содержится сегодняшняя или завтрашняя дата. Рас- познается большинство форм задания даты, например Dec. 7, december 7 и 12/7 (седьмое декабря), но не 7 December или 7/12. Если задано только число (например, 1), это будет означать соот- ветствующий день каждого месяца. Перед выходными днями «завтра» означает дни вплоть до понедельника включительно. Если задан параметр, служба calendar ищет файлы с именем calendar во всех регистрационных оглавлениях пользователей и посылает найденные строки пользователям через почтовую службу mail (1). cat — конкатенация и печать файлов САТ(1) cat I —u 1 файл ... Команда cat последовательно читает каждый файл и записы- вает его в файл стандартного вывода. Если не задано ни одного файла или если встретился параметр —, cat читает стандартный файл ввода. Если в качестве стандартного файла вывода задан не терминал, то осуществляется поблочная буферизация выво- димых данных, иначе — построчная буферизация. Опция —и отменяет всякую буферизацию. cb — форматирование С-программ СВ(1) cb Команда cb помещает в файл стандартного вывода копию С-программы из файла стандартного ввода. При этом выполня- ется разбивка и делаются отступы, отражающие структуру про- граммы. сс — компилятор языка С СС(1) сс [ опция 1 ... файл ... Команда сс представляет собой компилятор языка С системы UNIX. Считается, что параметры-файлы с именами, оканчиваю- щимися на .с, содержат исходные тексты С-программ. Эти файлы
304 Приложение 1. Команды компилируются, причем объектные модули помещаются в файлы с именами, образуемыми из имен исходных файлов заменой суф- фикса .с на .о. Файл .о обычно уничтожается, если компилиру- ется и одновременно загружается программа, состоящая из одного модуля. Аналогично считается, что параметры-файлы с именами, оканчивающимися на .s, содержат исходные программы на языке Ассемблера. Они ассемблируются с образованием файлов .о. Опции —с Не выполнять фазу загрузки и сохранить объектный файл даже в случае программы, состоящей только из одного модуля. —g Сгенерировать таблицу символов для отладчика sdb(l). —w Не выдавать предупредительную диагностику. —р Вставить в программу дополнительные команды для подсчета числа обращений к каждой подпрограмме. Кроме того, если выполняется фаза загрузки, заме- нить стандартную начальную подпрограмму на дру- гую, которая автоматически вызывает функцию monitor(3) при раскрутке и обеспечивает запись файла mon.out при нормальном завершении выполнения объектной программы. Используя prof(l), можно за- тем получить профиль выполнения программы. — О Вызвать оптимизатор объектного кода. — R Передается команде ассемблирования as, в резуль- тате чего инициализированные переменные становятся общедоступными, но только на чтение. — S Скомпилировать заданные С-программы с сохране- нием полученных ассемблерных модулей в соответст- вующих файлах с суффиксом .s. — Е Пропустить заданные С-программы только через макропрепроцессор. Результат поместить в файл стандартного вывода. — С Не исключать комментарии на этапе работы макро- препроцессора. — о выходной-файл Задание имени для результирующего файла с готовой программой. Если используется эта опция, файл a.out остается неизменным. — D имя=определение — D имя Определить имя для препроцессора по аналогии с конструкцией ф include. Если определение не за- дано, значением определяемой переменной становится
Приложение /. Команды 305 — U имя Аннулировать начальное определение для перемен- ной имя. —1 оглавление Включаемые (посредством 41= include) файлы, имена которых не начинаются с литеры /, всегда ищутся сначала в оглавлении, содержащем файл, затем в ог- лавлениях, заданных опциями —1, а затем в списке стандартных оглавлений. Остальные параметры являются либо опциями загрузчика, либо именами объектных модулей, совместимых с С-модулями. Как правило, это модули, полученные в результате предшествую- щих запусков команды сс. Это могут быть также библиотеки программ, совместимых сС-программами. Эти модули загружают- ся (в указанном порядке) наряду с модулями, полученными при компиляции, и образуется готовая программа с именем a.out. chmod — изменить полномочия CHMOD(l) chmod полномочия файл ... Полномочия каждого указанного файла изменяются согласно параметру полномочия. Полномочия могут задаваться в абсолют- ном или символическом виде. В абсолютном виде полномочия представляют собой восьмеричное число, получаемое при помощи операции логическое ИЛИ из значений, описанных в chmod(2). Символические полномочия имеют вид [ кто ] опер полномочие [ опер полномочие ] ... Часть кто представляет собой комбинацию из букв и (полномо- чия владельца), g (группы) и о (прочих пользователей). Буква а обозначает ago (все). Если часть кто опущена, подразумевается а, но в этом случае учитывается значение маски создания файлов (см. umask (2)). Операцией опер может быть + (добавить указанное полномо- чие к текущим полномочиям файла),— (исключить указанное полномочие) и = (задать в точности это полномочие, все осталь- ные биты будут отброшены). Часть полномочие представляет собой произвольную комби- нацию из букв г (чтение), w (запись), х (исполнение), s (установка идентификатора группы) и t (сохранение программного сегмента). Буквы и, g и о означают, что полномочие следует взять из те- кущих полномочий файла. Опускать полномочие имеет смысл только с операцией = для исключения всех полномочий.
306 Приложение 1. Команды Можно задавать несколько символических полномочий, разде- ляя их запятыми. Операции выполняются в указанном порядке. Букву s задавать имеет смысл только с и или g. Только владелец файла (или суперпользователь) может изме- нять его полномочия. стр — сравнение двух файлов СМР(1) стр [ —1 ] [ —s ] файл1 файл2 Сравниваются два заданных файла. Если вместо файла! задан знак —, используется файл стандартного ввода. При подразумева- емых значениях опций стр не выдает никакого сообщения, если файлы идентичны. Если файлы различаются, стр сообщает номер байта и номер строки, где имеются различия. Если один: из фай- лов является начальной подпоследовательностью другого файла, этот факт также отмечается. Опции —1 Печатать номер байта (в десятичном виде) и разли- чающиеся байты (в восьмеричном виде) для каждого различия. —s Не печатать сообщения о различии файлов; вернуть только код ответа. col — исключить переводы строки назад COL(l) col I —bfx 1 Команда col считывает данные из файла стандартного ввода и записывает результаты в файл стандартного вывода. Она вы- полняет преобразование текста таким образом, чтобы исключить литеры перевода строки назад (esc-7) и литеры сдвига вниз или вверх на полстроки (esc-9) и (esc-8). Команда col особенно по- лезна для обработки вывода в несколько колонок, порождаемого запросом .rt системы nroff, и результатов работы препроцессора tbl (1). Хотя команда col допускает во входном файле литеры сдвига вверх или вниз на полстроки, она обычно не выдает их в выход- ной файл. Вместо этого текст, который появился бы между стро- ками, сдвигается ниже на следующую строку. Эту трактовку ли- теры сдвига на полстроки можно отменить опцией —f; в этом случае в выводе команды col могут присутствовать литеры сдвига на полстроки вперед (esc-9), но все же в нем никогда не будет никакого рода литер перевода строк назад.
Приложение 1. Команды 307 Если задана опция —Ь, команда col предполагает, что ис- пользуемое устройство вывода не выполняет возврат на шаг. В этом случае из нескольких литер, которые должны появиться при выводе в одной и той же позиции, будет выведена только одна, считанная последней. Предполагается, что управляющие литеры so (016) и si (017) начинают и завершают текст, представленный в альтернативной кодировке литер. Кодировка (основная или альтернативная) каждой считанной неграфической литеры запоминается, и при выводе, где требуется, вставляются литеры so и si, обеспечиваю- щие правильную интерпретацию каждой литеры. Для сокращения времени печати команда col обычно преоб- разует последовательность пробелов в табуляции. Это преобра- зование не выполняется, если задана опция —х. Из входного файла удаляются все управляющие литеры, за исключением пробела, возврата на шаг, табуляции, возврата каретки, новой строки и литеры esc (033) со следующей за ней одной из литер 7, 8, 9, si, so или vt (013). Эта последняя литера является альтернативной литерой перевода на целую строку назад и служит для совместимости с другими аппаратными реа- лизациями. Все остальные неграфические литеры игнорируются. comm — выделить или исключить строки, общие для двух упо- рядоченных файлов comm [ — [ 123 ] ] файл1 файл2 СОММ(1) Команда comm читает файл1 и файл2, которые должны быть упорядочены лексикографически, и выполняет вывод в три ко- лонки. Первая колонка состоит из строк, содержащихся только в первом файле, вторая — из строк, содержащихся только во втором файле, а третья — из строк, общих для обоих файлов. Знак минус в роли имени файла означает файл стандартного ввода. Флаги 1, 2 и 3 отменяют печать соответствующей колонки. ср — копирование СР(1) ср файл! файл2 ср файл ... оглавление Содержимое файла! копируется в файл2. Если файл2 уже существует, его полномочия и владелец не изменяются. В против- ном случае полномочиями файла2 становятся полномочия файла файл1.
308 Приложение 1. Команды Команда ср во второй форме копирует один или несколько файлов в заданное оглавление, сохраняя их исходные имена. Команда ср отказывается копировать файл в себя. crypt — шифровка и дешифровка CRYPT(l) crypt [ пароль ] Команда crypt читает файл стандартного ввода и пишет в файл стандартного вывода. Пароль представляет собой ключ, определяющий конкретное преобразование. Если пароль не задан, команда crypt запрашивает ключ с терминала и на время его ввода выключает печать на терминале. Команда crypt вы- полняет шифровку и дешифровку по одному и тому же ключу: команды crypt ключ Сданные >шифровка crypt ключ <шифровка | рг распечатают данные в исходном виде. Файлы, зашифрованные при помощи crypt, можно редактиро- вать редактором ed в режиме с шифровкой. Надежность шифровки файлов зависит от трех факторов: базисный метод должен быть трудноразрешим, прямой перебор всех возможных ключей должен быть физически невозможен, следует минимизировать риск того, что ключ или исходный текст будут «подсмотрены». Команда crypt реализует однороторную машину, построенную на основе идей German Enigma, но с 256-элементным ротором. Методы дешифровки для таких машин не слишком широко из- вестны, и, кроме того, они требуют значительных усилий. Преобразование ключа во внутреннее представление машины сознательно сделано трудоемким, т. е. требующим существенных долей секунды на выполнение. Однако если длина ключа огра- ничена, скажем, тремя строчными буквами, то зашифрованный файл можно прочитать, затратив всего лишь несколько минут машинного времени. Поскольку ключ является параметром команды crypt, его в принципе могут увидеть пользователи, выполняющие команду ps {1) или производную от нее. Чтобы минимизировать вероят- ность такого события, crypt принимает меры для уничтожения записи ключа сразу же в начале работы. Наиболее уязвимыми местами команды crypt являются, без сомнения, выбор ключей и их сохранность.
Приложение 1. Команды 309 date — вывести или установить дату DATE(l) date Печатаются текущая дата и точное время. Система работает по гринвичскому времени, а команда date берет на себя заботу о преобразовании его в местное время и обратно. dd — преобразование и копирование файла DD(1) dd [ опция=значение ] ... Команда dd копирует заданный входной файл в заданный выходной файл, выполняя при этом, возможно, некоторые пре- образования. По умолчанию используются стандартные файлы ввода и вывода. Можно задавать размеры блоков для входного и выходного файлов, что позволяет выбирать их в соответствии с размерами физических блоков используемых устройств ввода- вывода. Опции задаются ключевыми словами. Опции if= Имя входного файла. По умолчанию исполь- зуется стандартный файл ввода. of= Имя выходного файла. По умолчанию ис- пользуется стандартный файл вывода. ibs=n Использовать входные блоки размером в п байт (по умолчанию 512). obs=n Использовать выходные блоки размером в п байт (по умолчанию 512). bs=n Установить размер входных и выходных бло- ков равным п. Эта опция заменяет ibs и obs. Она особенно эффективна, если никаких пре- образований не задано, так как в этом случае процесс копирования предельно упрощается. cbs=n < Размер буфера преобразований. skip=n Пропустить п входных записей, прежде чем начать копирование. files=n Пропустить п входных файлов, прежде чем начать копирование. seek=n Пропустить (при помощи функции Iseek (2)) п записей от начала выходного файла, прежде чем начать копирование. count=n Скопировать только и входных записей. conv=ascii Преобразовать литеры из кода EBCDIC в ASCII. ebcdic Преобразовать литеры из кода ASCII в EBC- DIC. block Преобразовать записи переменной длины в записи фиксированной длины.
310 Приложение 1, Команды unblock Преобразовать записи фиксированной длины в записи переменной длины. lease ucase swab noerror Преобразовать прописные буквы в строчные. Преобразовать строчные буквы в прописные. Поменять местами каждую пару байтов. Не прекращать работу при ошибках ввода- вывода. sync Дополнить каждую входную запись до раз- мера ibs. ..., ... Несколько преобразований, разделенных за- пятыми. Все размеры задаются в байтах. За размером может следо- вать одна из букв к, b или w, что означает умножение на 1024, 512 и 2 соответственно. Пара чисел может быть разделена лите- рой х, что означает произведение. Опция cbs используется, только если задано преобразование ascii, unblock, ebcdic или block. В первых двух случаях в буфер преобразований помещается cbs литер, выполняется требуемое преобразование, отбрасываются завершающие строку пробелы, добавляется литера новой строки и строка посылается в файл вывода. В трех последних случаях текст считывается в буфер преобразований и дополняется справа пробелами до длины выходной записи cbs. После завершения выполнения задания dd сообщает коли- чество полных и неполных входных и выходных блоков,. deroff — удалить из текста все nroff, troff, DEROFF(l) tbl и eqn конструкции. deroff [ —w ] файл ... Команда deroff читает каждый входной файл и удаляет из него все строки, содержащие запросы nroff и troff, конструкции, вводимые литерой обратная косая черта, макроопределения, конструкции eqn (строки между .EQ и .EN и текст между разде- лителями) и описания таблиц. Оставшийся текст записывается в файл стандартного вывода. Команда deroff прослеживает це- почку включаемых файлов (запросы .so и .пх). Если файл уже был включен, запрос .so игнорируется, а .пх вызывает заверше- ние работы. Если не задано ни одного входного файла, deroff считывает файл стандартного ввода. Если задан флаг —w, то результатом является список слов, по одному слову в строке. Слово представляет собой цепочку букв, цифр и апострофов, начинающуюся с буквы; апострофы
Приложение 1. Команды 311 удаляются. Все остальные литеры в тексте игнорируются. В про- тивном случае выходной файл соответствует оригиналу. df — информация о свободном пространстве на диске DF(1) df файловая-система Команда df печатает количество свободных блоков в указан- ной файловой системе, например в /dev/грОа. Если файловая система не задана, печатается размер свободного пространства во всех смонтированных файловых системах. Единицей измерения пространства в команде df являются физические блоки файловой системы. В некоторых версиях сис- темы UNIX физические блоки состоят из 1024 байт и вмещают два (логических) блока, используемых в качестве единицы из- мерения пространства в команде du(l) и в команде ls(l) с опцией —s. diction, explain — распечатать многословные фразы, тезаурус для diction DICTION(l) diction [ —ml ] [ —mm ] [ —n ] [ —f файл-образцов ] файл ... explain Команда diction находит в тексте документа все предложения, содержащие фразы из базы данных плохо построенных и много- словных фраз. Каждая найденная фраза заключается в квадрат- ные скобки [ ]. Поскольку diction перед просмотром текста обра- батывает его командой deroff, во входной файл следует включать форматирующие файлы заголовков. Подразумеваемым пакетом является пакет—ms.Опция —mm задает макробиблиотеку —mm. Флаг —ml заставляет deroff пропускать списки; этот флаг сле- дует использовать, если в документе содержится много списков, элементы которых не являются предложениями. При помощи опции —f файл-образцов пользователь может задать свой соб- ственный файл фраз в дополнение к подразумеваемому файлу. Если, кроме того, задан флаг —п, то подразумеваемый файл не • будет использоваться. Команда explain представляет собой интерактивный тезаурус для фраз, найденных с помощью команды diction. diff — поиск различий в файлах DIFF(l) diff [ опция 1 файл! файл2 Команда diff выводит те строки файлов, которые нужно из- менить для того, чтобы привести файлы в соответствие друг
312 Приложение /. Команды с другом. За исключением редких случаев, diff находит мини- мальный достаточный набор различий. Если файл! или файл2 за- дан знаком минус, то используется файл стандартного ввода. Формат вывода управляется несколькими опциями. В стан- дартном формате выводимые строки имеют вид п1 а пЗ,п4 п1,п2 d пЗ п1,п2 с пЗ,п4 Эти строки напоминают запросы редактора ed для преобразова- ния файла! в файл2. Номера после буквы относятся к файлу2. Заменяя а на d и читая наоборот (справа налево), можно также выяснить, как преобразовывать файл2 в файл!. Как и в редакто- ре ed, пары одинаковых чисел п1=п2, пЗ=п4 сокращенно запи- сываются в виде одного числа. Вслед за каждой такой строкой идут все затрагиваемые за- данным в ней действием строки из первого файла с пометкой <, а затем — все затрагиваемые данным действием строки из вто- рого файла с пометкой >. За исключением опции —Ь, которую можно задавать вместе с любой другой опцией, опции команды diff взаимоисключают друг друга. Опции —е Сгенерировать для редактора ed командный файл с за- просами a, end, который будет воссоздавать файл 2 из файла!. —h Выполнить задание быстрым, но не очень надежным методом. Этот метод годится, когда файлы имеют нео- граниченную длину, а отличия в них невелики и хо- рошо различаются. —b Проигнорировать пробелы и табуляции в конце строк; остальные цепочки пробелов и табуляций считать одинаковыми. du — справка об использовании дискового пространства DU(1) du [ —s ] [ —а ] [ имя ... ] Команда du для каждого заданного имени файла или оглав- ления выдает количество блоков, занимаемых на диске этим файлом или всеми файлами и (рекурсивно) всеми подоглавления- ми данного оглавления. Если имена файлов не заданы, выдается информация для файлов из текущего оглавления.
Приложение 1. Команды 313 Если задан необязательный параметр —s, то выдается только итоговая справка. Если задан необязательный параметр —а, то информация выдается для каждого файла. При отсутствии обоих параметров информация выдается только по каждому оглавлению. Пространство, занимаемое файлом, на который имеются две или более ссылок, учитывается только один раз. echo — эхо ЕСНО(1) echo [ — п ] [ парам 1 ... Команда echo переписывает в стандартный файл вывода свои параметры, разделяя их пробелами и заканчивая список лите- рой новой строки. Если задан флаг —п, литера новой строки не добавляется. ed — редактор текстов ED(1) ed [ — ] [ —х ] [ имя ] Это стандартный редактор текстов. Если задано имя, ed выполняет команду е для файла с этим именем; иными словами, указанный файл считывается в буфер редактора, так что можно будет сразу приступить к его редак- тированию. Если присутствует опция —х, предварительно вы- полняется запрос х для обработки зашифрованного файла. Оп- ция — подавляет печать пояснительных сообщений; ее следует использовать, когда стандартным вводом является файл с коман- дами редактирования. При получении сигнала прерывания ed печатает сообщение ?interrupted и переходит к считыванию очередной команды. Не- которые ограничения. Максимальная длина строки — 512 литер, длина списка команд в глобальной команде — до 256 литер, имя файла может иметь длину до 64 литер. В минимашинах времен- ный файл может занимать до 128К байт. Максимальное число строк редактируемого файла зависит от размера наличной памяти. При считывании файла ed исключает пустые литеры (код О в ASCII) и все литеры после последней литеры новой строки. Файлы, содержащие неграфические литеры, не считываются. eqn, neqn — подготовка математических формул EQN(l) eqn [ файл ] ... Команда eqn представляет собой препроцессор к системе troff(1) для подготовки в тексте математических формул при
314 Приложение 1. Команды печати на фотонаборном устройстве Graphic Systems. Команда neqn предоставляет аналогичные средства, но ее вывод подходит и для терминалов. Приведем типичный способ использования этих команд: eqn файл ... | troff neqn файл ... | nroff Если не задано ни одного файла, eqn и neqn считывают файл стандартного ввода. ехрг — вычислить выражение, составленное из параметров EXPR(l) ехрг парам ... Параметры команды рассматриваются как единое выражение. После вычисления этого выражения его результат записывается в файл стандартного вывода. Каждый элемент выражения яв- ляется отдельным параметром. Ниже перечислены допустимые операции и ключевые слова. Список составлен в порядке возрастания приоритетов. Операции с одинаковыми приоритетами собраны в группы. выражение | выражение Результатом является значение первого выражения, если оно от- лично от 0 и пустой цепочки, и значение второго выражения в противном случае. выражение & выражение Результатом является значение первого выражения, если оба вы- ражения отличны от 0 и пустой цепочки, и 0 в противном случае. выражение опер выражение Результатом является 1, если заданное сравнение истинно, и О, если оно ложно. Операцией опер может быть одна из операций < <= = ! = >= >. Сравне- ние является арифметическим, если оба выражения — целые числа, и лексикографическим в противном случае. выражение + выражение выражение — выражение Сложение и вычитание параметров. выражение * выражение выражение / выражение выражение % выражение Умножение, деление и взятие ос- татка от деления параметров.
Приложение 1. Команды 315 выражение : выражение Операция сопоставления с об- разцом, сравнивающая цепочку литер — первый параметр с ре- гулярным выражением — вто- рым параметром. Синтаксис ре- гулярного выражения такой же, как в редакторе ed(l). Для выделения подцепочки из первого параметра можно ис- пользовать комбинации \( и \). В противном случае результатом операции сопоставления являет- ся количество сопоставившихся литер (0 при неудаче). (выражение) Скобки для подвыражений. f77 — компилятор языка Фортран 77 F77(l) f77 [ опция ] ... файл ... Параметры, оканчивающиеся на .f, считаются именами фай- лов, содержащих исходные программы на языке Фортран 77. Они компилируются; объектные модули помещаются в файлы текущего оглавления, имена которых получаются из имен ис- ходных файлов заменой Л на .о. Параметры, оканчивающиеся на .г или .е, считаются именами исходных файлов с программами на языках Ratfor и EFL соот- ветственно. Они предварительно преобразуются соответствую- щим препроцессором, а затем компилируются компилятором Фортрана 77. Аналогичным образом параметры, оканчивающиеся на .с и .s, считаются именами файлов, содержащих исходные программы на языке С и языке ассемблера. Эти файлы компилируются и ассемблируются с образованием файлов .о. Опции Следующие опции имеют тот же смысл, что и в команде сс(1). Описание опций, действующих на этапе загрузки, смотрите в ld(l). —с Не выполнять загрузку и сгенерировать файлы .о для всех исходных файлов. —g Сгенерировать таблицу литер для sdb(l). Кроме того, при вызове загрузчика ld(l) задается флаг —1g.
316 Приложение 1. Команды —w Не выдавать никаких предупредительных сообщений. Если эта опция имеет вид —w66, то подавляются толь- ко сообщения о несовместимости с Фортраном 66. <—р Подготовить объектный файл для профилирования (см. prof(l)). —О Вызвать оптимизатор объектного кода. — S Компилировать заданные программы с сохранением получаемых ассемблерных модулей в соответствующих файлах с суффиксом .s. (Файлы .о не создаются.) —о выходной-файл Задать другое имя для результирующего файла (вместо a.out). Следующие опции специфичны для f77. —one trip Скомпилировать циклы DO таким образом, чтобы при получении управления они выполнялись по крайней мере один раз. (В Фортране 77 циклы DO не выполняются совсем, если верхнее значение переменной цикла меньше нижнего.) —и Считать неописанные переменные неопределенными, вместо того чтобы присваивать им подразумеваемые типы по правилам Фортрана. —С Сгенерировать код, проверяющий, что значения ин- дексов находятся в пределах описанных границ мас- сивов. — F Применить препроцессор языка EFL или Ratfor к соответствующим файлам и поместить резуль- таты в файлы с суффиксом Л, не выполняя компи- ляции. —Е х При обработке файлов .е использовать опции пре- процессора EFL, заданные в цепочке х. — R х При обработке файлов .г использовать опции пре- процессора Ratfor, заданные в цепочке х. Остальные параметры являются либо опциями загрузчика, либо именами объектных модулей, совместимых с модулями на Фортране 77. Как правило, это модули, полученные в результате предшествующих компиляций. Это могут быть также библиотеки программ, совместимых с программами на Фортране 77. Эти модули загружаются (в указанном порядке) наряду с модулями, полученными при компиляции, и образуется готовая программа с именем a.out. find — найти файлы find список-составных-имен выражение F1ND(1)
Приложение 1. Команды 317 Команда find для каждого составного имени, заданного в списке-составных-имен, рекурсивно обходит определяемую этим именем иерархию оглавлений в поисках файлов, удовлетворяю- щих заданному логическому выражению. Логическое выражение строится из первичных выражений, описания которых приво- дятся ниже. В этих описаниях параметр п используется для указания целого десятичного числа, причем +п означает «боль- ше чем п», —п означает «меньше чем п», а п означает «в точности п». —паше имя-файла Истина, если параметр имя-файла совпа- дает с именем (name) текущего файла. Обычные правила, принятые для языка- оболочки, можно применять для отмены специальных значений литер (обратите внимание на литеры [, ? и *). —perm опит Истина, если полномочия файла в точности совпадают с восьмеричным числом опит (см. chmod (1)). Если перед опит стоит знак минус, то при сравнении учитывается большее количество флагов; точнее, ис- пользуется маска 017777 (см. stat(2)) и проверяется условие (flags&onum)= = onum. —type с Истина, если файл имеет тип, определяемый литерой с, с может быть одной из букв Ь, с, d или f, что означает блочный специаль- ный файл, текстовый специальный файл, оглавление или обычный файл соответст- венно. —links п Истина, если на файл имеется п ссылок. —user имя Истина, если владельцем файла является пользователь имя, где имя — либо реги- страционное имя пользователя, либо его идентификатор (число). —group имя Истина, если файл принадлежит группе имя, где имя — либо имя группы, либо ее идентификатор (число). —size п Истина, если файл занимает п 512-литер- ных блоков. —inum п Истина, если файл имеет номер индекс- ного узла п. —atime п Истина, если к файлу были обращения в течение последних п дней. —mtime п Истина, если файл изменился в течение последних п дней.
318 Приложение 1. Команды —ехес cmd ; Истина, если команда cmd после выпол- нения возвращает нуль в качестве ста- туса завершения. Команда cmd должна заканчиваться точкой с запятой, специ- альное значение которой обычно отме- няется, чтобы предотвратить ее интерпре- тацию программой-оболочкой как конца команды find. Параметр {} команды cmd перед выполнением заменяется на состав- ное имя текущего файла. —ok cmd ; Аналогична —ехес, но порождаемая ко- манда выводится в файл стандартного вывода, а затем считывается строка из файла стандартного ввода. Команда вы- полняется только в случае, если эта строка содержит ответ у («да»). —print Истина всегда; вызывает печать состав- ного имени текущего файла. —newer имя-файла Истина, если текущий файл в последний раз был изменен позднее, чем файл, имя которого задано в качестве параметра. Эти первичные выражения (р) можно объединять при помощи следующих операций (в порядке уменьшения приоритета): (...) Заключенная в скобки группа первичных выражений, связанных операциями (скобки имеют специальное зна- чение для программы-оболочки, которое должно быть отменено). !р Знак ! представляет собой унарную операцию отри- цания. р р Конкатенация первичных выражений. Если первич- ные выражения располагаются друг за другом, под- разумевается, что они связаны логической операцией «и» (and). р —о р Альтернативные первичные выражения. Операция —о означает логическое «или» (or). grep, egrep, fgrep — поиск в файле по образцу GREP(l) grep [ опция ... ] выражение [ файл ] ... egrep [ опция ... ] [ выражение ] [ файл ] ... fgrep [ опция ... ] [ подцепочки ] [ файл ] ... Команды семейства grep сканируют заданные входные файлы (по умолчанию — файл стандартного ввода) в поисках строк, соответствующих некоторому образцу. Каждая найденная стро-
Приложение 1. Команды 319 ка, как правило, копируется в файл стандартного вывода. Об- разцы, используемые командой grep, являются ограниченными регулярными выражениями и аналогичны образцам в редакторе ed(l); grep использует компактный недетерминированный алго- ритм. Образцами в команде egrep могут быть произвольные регу- лярные выражения; используется быстрый детерминированный алгоритм, однако размер требуемой для работы этого алгоритма памяти определяется иногда экспоненциальной зависимостью. В fgrep образцами являются обычные цепочки литер, а исполь- зуемый алгоритм является и быстрым, и компактным. Опции —с Напечатать только общее число найденных строк. —е выражение То же самое, что и просто параметр выраже- ние; применяется, если выражение начина- ется со знака минус. —f файл Регулярное выражение (egrep) или спи- сок подцепочек (fgrep) взять из указанного файла. —h Не печатать имя файла перед выдаваемыми строками. —i При выполнении сравнений игнорировать раз- мер букв, т. е. считать прописные и строчные буквы одинаковыми (только для grep и fgrep). В некоторых версиях системы UNIX эта оп- ция называется —у. —I Напечатать имена файлов, содержащих строки, сопоставляющиеся с образцом. Имена файлов выдаются только по одному разу и разде- ляются литерой новой строки. —п Перед каждой строкой выводить ее номер в дан- ном файле. —s Выполнить команду «молча». Никаких сооб- щений не выводится (кроме сообщений об ошибках). Этот режим полезен, когда требу- ется только проверить статус завершения. —v Напечатать все строки, которые не сопостав- ляются с данным образцом. —х Напечатать только строки, которые полностью сопоставляются с образцом (только для fgrep). Если входных файлов несколько, то во всех случаях перед выводимыми строками выводится имя соответствующего файла. Следует соблюдать осторожность при использовании в регуляр-
320 Приложение 1. Команды ном выражении литер $ * [ Л | ( ) и \fR, так как они имеют особый смысл и в языке-оболочке. Самое надежное — заключить весь параметр в одиночные кавычки ". Команда fgrep ищет строки, содержащие одну из заданных подцепочек (разделителем подцепочек служит литера новой строки). Команда egrep воспринимает расширенное регулярное выра- жение, описанное в гл. 8. join — операция соединения в реляционной базе данных JOIN(l) join [ опции ] ... файл! файл2 Команда join формирует в файле стандартного вывода соеди- нение двух отношений, задаваемых строками файлов файл! и файл2. Если вместо имени файла! указан знак минус, использу- ется файл стандартного ввода. Файлы файл! и файл2 должны быть упорядочены лексикогра- фически по значениям полей, по которым будет выполняться соединение. Обычно это первое поле в каждой строке. Для каждой пары строк из файла! и файла2, имеющих оди- наковые значения полей, по которым выполняется соединение, формируется одна выходная строка. Обычно она состоит из этого поля, за ним следуют оставшиеся поля строки из файла!, а затем оставшиеся поля строки из файла2. Поля обычно разделяются пробелами. Несколько разделите- лей подряд рассматриваются как один, а начальные раздели- тели отбрасываются. Опции —а п В дополнение к обычному выводу выдать непар- ные строки из файла п, где п равно 1 или 2. —е s Заменить пустые результирующие поля цепоч- кой s. —j п tn Выполнить соединение по полю т файла п. Если п опущено, использовать m-е поле каждого файла. —о список Каждую выходную строку составить из полей, за- данных в списке. Каждый элемент списка имеет вид п.ш, где п — номер файла, ат — номер поля. —t с Использовать в качестве разделителя полей ли- теру с. Значимыми являются все вхождения ли- теры с в строку. kill — завершить процесс KILL(l)
Приложение /. Команды 321 kill [ — сиг ] идентификатор-процесса ... Команда kill посылает указанному процессу сигнал сиг. Если сигнал не задан (т. е. первый параметр — не сигнал), посыла- ется сигнал программного завершения SIGTERM (15). Сигнал программного завершения уничтожит процесс, если последний его не перехватит. Команда kill —9 ... гарантирует уничтожение процесса, так как этот сигнал не мо- жет быть перехвачен. По соглашению, если в качестве номера процесса задан 0, сигнал передается всем процессам данной группы (т. е. всем процессам, порожденным в ходе текущего се- анса работы в системе). Уничтожаемые процессы должны при- надлежать тому же пользователю. Id — редактор связей (загрузчик) LD(1) Id [ опция ] ... файл ... Редактор связей Id объединяет несколько объектных модулей в один, разрешает внешние ссылки и осуществляет поиск в биб- лиотеках. В простейшем случае задается несколько объектных файлов, и Id объединяет эти файлы, образуя один объектный модуль, который можно либо выполнить, либо использовать в качестве входного параметра при последующих обращениях к Id (в последнем случае должна быть задана опция —г для со- хранения признаков перемещаемых адресов). Результат работы Id помещается в файл a.out. Этот файл становится выполнимым, только если в процессе загрузки не было ошибок. Модули-параметры размещаются друг за другом в указан- ном порядке. Точкой входа результирующей программы явля- ется начало первого модуля (если только не задана опция —е). Если какой-либо параметр является библиотекой, просматри- вается эта библиотека. Просмотр осуществляется ровно один раз в момент времени, определяемый позицией библиотеки в спис- ке параметров. Загружаются только те подпрограммы из биб- лиотеки, которые определяют еще не разрешенные внешние ссылки. Если библиотечная подпрограмма ссылается на другую подпрограмму из этой библиотеки и эта библиотека не обработана командой ranlib(l), то вторая подпрограмма должна быть распо- ложена в библиотеке где-нибудь после первой. Таким образом, порядок подпрограмм в библиотеке может быть существенным. Первым элементом библиотеки может быть файл с именем _.SYMDEF, который считается оглавлением библиотеки и ге- нерируется командой ranlib(l); в этом случае это оглавление просматривается циклически до тех пор, пока не будет разре- шено максимальное количество ссылок. 11с. Баурн
322 Приложение 1. Команды Символы _etext, _edata и _end (etext, edata и end в програм- ме на языке С) являются зарезервированными. В программе им соответствуют адрес первой ячейки после программного кода, адрес первой ячейки после области инициализированных данных и адрес первой ячейки после всей области данных. Определение этих символов в программе является ошибкой. Опции —d Требуется определить общую область, даже если задан флаг —г. —е Следующий параметр интерпретировать как имя точки входа в загружаемую программу. Подразуме- ваемой точкой входа является 0. —ix Эта опция есть сокращение имени библиотеки /lib/libx.a, где х—цепочка литер. Если такой библиотеки нет, делается попытка использовать /usr/lib/libxa. Так как библиотека просматривается тогда, когда ее имя встречается в списке параметров, позиция опции —1 в списке параметров является существенной. —М Сгенерировать простую таблицу загрузки, содер- жащую имена загружаемых файлов. —п Сделать так, чтобы при выполнении результирую- щего файла его программный сегмент был защищен от записи и использовался совместно всеми пользо- вателями, выполняющими этот файл. —о Вместо файла a.out поместить готовую программу в файл с именем, заданным следующим за опцией —о параметром. —г Включить в результирующий файл биты перемеще- ния, что позволяет использовать этот файл в дру- гом обращении к Id. Кроме того, этот флаг отме- няет окончательное присваивание значений общим символам и подавляет диагностику о неопределен- ных символах. — S Удалить из результирующего файла все символы, кроме локальных и глобальных. —s Удалить из результирующего файла таблицу сим- волов и биты перемещения (это позволяет сэконо- мить пространство за счет части услуг, предостав- ляемых отладчиками). Эту информацию можно также удалить командой strip(l). —и Считать следующий параметр символом и вставить его в таблицу символов как неопределенный символ. Эта опция используется при загрузке целиком ив
Приложение 1. Команды 323 библиотеки, так как первоначально таблица симво- лов пуста, а для того, чтобы начать загрузку первой подпрограммы, требуется неразрешенная ссылка. —X Сохранить локальные символы, за исключением тех, имена которых начинаются с L. Эта опция исполь- зуется компилятором сс(1) для того, чтобы отбро- сить сгенерированные самим компилятором внут- ренние метки перехода, сохранив в то же время локальные символы подпрограмм. —х Вставить в выходную таблицу символов только внешние символы и не помещать в нее локальные (неглобальные) символы. Эта опция позволяет сэкономить пространство в результирующем файле. learn — автоматизированная система обучения для пользовате- лей LEARN(l) learn [ тема [ урок [ сложность 1 1 1 Автоматизированная система обучения learn дает курс лекций и практических занятий по использованию системы UNIX. Для начала просто наберите слово learn. Программа будет задавать вам вопросы, пытаясь понять, что вы хотите. Вопросов не будет, если вы зададите имя темы и номер последнего урока, пройден- ного вами в предыдущем сеансе работы с learn. Вы можете также указать в команде уровень сложности, который выводится сис- темой learn вместе с номером урока (но без скобок, в которые его заключает learn). Если вместо урока задан знак —, то learn будет запрашивать у вас номер каждого урока (это полезно для отлад- ки). Сеанс завершается специальной командой bye. В настоящее время имеются следующие темы: редактор (edi- tor), eqn, работа с файлами (files), макрокоманды (macros), до- полнительные сведения о файлах (morefiles), язык С. lex — генератор программ лексического анализа LEX(l) lex ( опция ] [ файл 1 ... Система lex генерирует программы, которые можно исполь- зовать для простого лексического анализа текста. Входные фай- лы (по умолчанию — файл стандартного ввода) содержат регу- лярные выражения, которые следует распознавать, и действия (в виде операторов языка С), которые следует выполнять при обнаружении данных регулярных выражений. Генерируется программа 1ех.уу.с на языке С. Ее следует откомпилировать посредством 11*
324 Приложение 1. Команды сс lex.yy.c —11 Во время выполнения этой программы для каждого распознан- ного регулярного выражения выполняется соответствующее действие (операторы языка С), а нераспознанные фрагменты входного текста копируются в выходной файл. Опции —t Поместить результат в файл стандартного вывода вместо lex.yy.c. —v Выдать строку, содержащую статистическую свод- ку о сгенерированном анализаторе. —п Противоположно —V. Стандартным является —и. —f Ускоренная компиляция. Построенные таблицы не упаковываются. Годится только для маленьких программ. lint — верификатор С-программ LINT(l) lint [ опция ] файл ... Система lint пытается обнаружить в заданных файлах, со- держащих С-программы, конструкции, которые, возможно, яв- ляются ошибочными, непереносимыми или излишними. Она так- же выполняет более строгую по сравнению с компиляторами проверку типов в программе. Среди обнаруживаемых конструк- ций — недостижимые операторы; циклы, вход в которые осу- ществляется не с начала; описанные, но неиспользованные авто- матические переменные; логические выражения с постоянными значениями. Кроме того, проверяется использование функций и обнаруживаются функции, возвращающие значение в одном месте, но не возвращающие его в другом месте; функции, вызы- ваемые с различным количеством параметров; функции, значе- ния которых не используются. По умолчанию подразумевается, что все файлы должны за- гружаться вместе; они проверяются на взаимную совместность. Системе lint доступны описания функций для некоторых биб- лиотек. Ссылки на эти библиотеки осуществляются с помощью обычных имен, например —1m, как это делается в команде ld(l). Опции Можно задать одновременно произвольное число опций из приве- денного ниже списка. Распознаются также опции —D, —Uh —1 команды сс(1), заданные в виде отдельных параметров. —а Сообщать о присваиваниях длинных значений пере- менным целого типа int.
Приложение 1. Команды 325 —Ь Сообщать о недостижимых операторах break. (Эта опция не является подразумеваемой, так как, к не- счастью, большинство программ, сгенерированных системами lex и уасс, содержат десятки таких опе- раторов.) —с Информировать об использовании конструкций пре- образования типов, если переносимость этих пре- образований сомнительна. —h Применить набор эвристических тестов с целью по- пытаться «поймать» ошибки, улучшить стиль и сократить излишний код. —п Не выполнять проверку на совместимость со стан- дартной библиотекой. —р Попытаться проверить переносимость на диалекты языка С, используемые в IBM и GCOS. —-и Не выдавать сообщения о переменных и функциях, используемых, но не определенных или определен- ных, но не используемых (эта опция удобна, когда при обращении к lint задается подмножество фай- лов, составляющих одну большую программу). —V Не выдавать сообщений о неиспользуемых парамет- рах функций. —х Сообщать о переменных, описанных как extern, но нигде не используемых. Системная функция exit(2) и другие функции, возврата из которых не бывает, системой lint не распознаются. Это может вызвать ложную диагностику. На поведение системы lint влияют некоторые специальные комментарии в тексте исходной программы. /* NOT REACHED*/ В соответствующих точках блокирует диагностику о недостижимых операторах. /*VARAGS и*/ Подавляет обычную проверку на соответствие ко- личества параметров вызова для функции, описа- ние которой следует ниже. Проверяются типы дан- ных для первых п параметров. Если п опущено, оно считается равным 0. /*NOSTRICT*/ Отключает строгую проверку типов при анализе следующего выражения. /*ARGSUSED*/ Включает опцию —v для следующей функции. .
326 Приложение 1. Команды /*LINTLIBRARY*/ В начале файла отключает сообщения о неисполь- зуемых функциях для этого файла. In — создание ссылок на файлы LN(1) In имя! [ имя2 ] Ссылка — это элемент оглавления, указывающий на файл. На один и тот же файл (включая его размер, всю информацию о правах доступа и т. д.) может быть несколько ссылок. Невоз- можно отличить новую ссылку на файл от исходного элемента оглавления. Файл можно изменять одинаково эффективно неза- висимо от имени, по которому осуществляется доступ к нему. Команда In с одним или двумя параметрами создает ссылку на существующий файл имя1. Если задано имя2, ссылка полу- чает это имя. Запрещается создавать ссылки на оглавления и на файлы из других файловых систем. login — вход в систему LOGIN(l) login [ имя-пользователя ] Команда login используется для первоначального входа в систему. Ею можно также воспользоваться в любой момент для того, чтобы войти в систему под другим именем. Если login вызывается без параметров, она запрашивает имя пользователя и, если оно введено верно, пароль. По возможности эхо-печать на время ввода пароля выключается, так что пароль не появится в протоколе сеанса. После успешного входа в систему пользователь извещается о наличии почты, и распечатываются новости дня. В ходе выполнения команды login согласно спецификациям, взятым из файла паролей, устанавливаются идентификаторы пользователя и группы и текущее (рабочее) оглавление, а затем вызывается интерпретатор команд (обычно sh(l)). Нулевым па- раметром при вызове интерпретатора команд является —sh, или, в общем случае, имя интерпретатора команд со знаком минус. Команда login устанавливает также первоначальную среду и помещает в нее имя регистрационного оглавления, имя интер- претатора команд, тип терминала (если он известен) и имя поль- зователя. Команда login распознается интерпретатором команд sh(l) и выполняется непосредственно, без образования нового про- цесса.
Приложение 1. Команды 327 look — найти строку в упорядоченном списке LOOK(l) look [ —df ] цепочка [ файл ] Команда look просматривает упорядоченный файл и печатает все строки, начинающиеся с цепочки. Используется бинарный поиск. Если файл не задан, предполагается /usr/dict/words. Опции —d Лексикографический порядок, используемый в сло- варях: в сравнении участвуют буквы, цифры, табу- ляции и пробелы. —f При сравнении прописные буквы отождествляются со строчными. lorder — построить отношение порядка для библиотеки объект- ных модулей LORDER(l) lorder файл ... Исходные данные — один или несколько объектных или биб- лиотечных (см. аг(1)) файлов. В стандартный вывод выдается список пар имен файлов. Каждая пара означает, что в первом файле имеется ссылка на внешние идентификаторы, определенные во втором файле. Чтобы получить порядок модулей в библиотеке, годящийся для однопроходного просмотра загрузчиком ld(l)» этот вывод можно обработать командой tsort(l). Необходимость в команде lorder отпадает при использовании команды ranlib(l), которая преобразует последовательный архив в библиотеку с произвольным доступом. 1рг — накопитель для устройства построчной печати LPR(l) Ipr [ опция 1 [ файл ... ] Команда 1рг ставит указанные файлы в очередь на печать. Если ни одного файла не задано, читается файл стандартного ввода. Опция —ш вызывает посылку уведомления пользователю через почтовую службу mail(l) по завершению выполнения печати. 1s — распечатать оглавление 1s [ опция 1 имя ... LS(1)
328 Приложение 1. Команды Для каждого параметра-оглавления 1s выдает информацию об элементах этого оглавления. Для каждого параметра-файла 1s повторяет его имя и выдает, если требуется, прочую информа- цию о файле. По умолчанию выводимые результаты сортируются в алфавитном порядке. Если ни одного параметра не задано, выдается информация об элементах текущего оглавления. Если задано несколько параметров, эти параметры сначала сорти- руются в соответствующем порядке, но параметры-файлы всегда предшествуют оглавлениям и их содержимому. Опции Различные версии команды Is отличаются друг от друга форма- тами вывода информации, а в некоторых версиях имеются опции, отсутствующие в данном списке. - —1 Выдавать информацию в «длинном» формате. Для каждого файла выдаются полномочия, количество ссылок на него, имя владельца, размер в байтах, время последней модификации. — t Сортировать вывод по времени последней модифи- кации файлов, а не как обычно по их именам. Пер- вым выводится файл, модифицированный самым последним. — а Вывести сведения о всех элементах оглавления; обычно сведения об элементах . и .. не выдаются. — s Для каждого элемента оглавления выдавать раз- мер файла в блоках. — -d Если имя является именем оглавления, вывести только это имя, не перечисляя содержимое оглав- ления (обычно используется с опцией —1, чтобы получить информацию о самом оглавлении). — г Изменить порядок сортировки на обратный. В ре- зультате порядок вывода будет противоположным алфавитному (при сортировке по именам) или же первым станет «самый старый» файл (при сорти- ровке по временам). — и Использовать время последнего обращения к файлу вместо времени последней модификации для сор- тировки (—t) или при выводе (—1). —с Использовать время создания файла для сорти- ровки или при выводе. — i Для каждого файла вывести в первой колонке номер его индексного узла. — f Интерпретировать каждый параметр как оглавле- ние и выдать список элементов этого оглавления.
Приложение 1. Команды 329 Эта опция отменяет опции —I, —-t, —s и —г и ус- танавливает опцию —а. Список выводится в том же порядке, в каком располагаются элементы в дан- ном оглавлении. —g В длинном формате выдавать идентификатор груп- пы вместо идентификатора владельца. mail — почтовая служба MAIL(l) mail [ —г ] [ —f файл ] Команда mail без параметров печатает, письмо за письмом, текущую корреспонденцию пользователя. Первым выдается письмо, полученное последним. Опция —г меняет порядок про- смотра корреспонденции на обратный. Для каждого письма mail считывает строку из стандартного файла ввода, в которой может содержаться одна из следующих команд: возврат каретки d Р s [ файл ] ... w [ файл ] ... m [ адресат ] ... конец-файла q \crnd Перейти к обработке следующего письма. Уничтожить письмо и перейти к обра- ботке следующего письма. Выдать письмо еще раз. Вернуться к предыдущему письму. Сохранить письмо в указанных файлах (по умолчанию — в файле mbox). Сохранить письмо без «шапки» в указан- ных файлах (по умолчанию — в файле mbox). Послать письмо указанным адресатам (по умолчанию — самому себе). Возвратить необработанные письма в поч- товый ящик и завершить работу. То же, что и конец-файла. Выполнить системную команду cmd. Прерывания обычно вызывают выход из почтовой службы; почтовый файл не изменяется. Если задана опция —i, почтовая служба игнорирует прерывание. Когда заданы адресаты, mail читает текст письма (вплоть до признака конца файла или строки, состоящей из одной точки) из файла стандартного ввода и переписывает его в почтовые файлы адресатов. Перед письмом помещаются имя отправителя и почтовый штемпель. Перед строками, которые выглядят как почтовый штемпель, помещается знак >. Именем адресата обыч- но является имя, под которым пользователь зарегистрирован в системе (см. login(l)). Для указания получателя в удаленной
330 Приложение 1. Команды системе перед его именем помещается имя этой системы и воскли- цательный знак (см. uucp(l)). Если задана опция —f, то вместо почтового ящика обрабаты- вается указанный файл (например, mbox). make — поддержка групп программ МАКЕ(1) make [ —f make-файл I [ опция ] ... файл ... Система make обновляет один или несколько целевых фай- лов, выполняя команды из make-файла. Файл обычно содержит программу. Если опция —f не задана, то делается попытка ис- пользовать файлы с именами makefile и Makefile (в этом порядке). Если вместо make-файла задан знак —, берется файл стандарт- ного ввода. Можно задавать несколько опций —f. Если в make-файле не задано специальное целевое имя JGNORE, то команды, возвращающие ненулевой статус завер- шения, приводят к прекращению работы системы make. Сигналы прерывания и выхода вызывают уничтожение целе- вого файла, если только он не зависит от специального имени .PRECIOUS. Опции —i- Эквивалентно специальной записи .IGNORE:. —к Если команда возвращает ненулевой статус завер- шения, прервать обработку текущей записи, но продолжить обработку других записей, не завися- щих от текущей записи. —п Отследить и напечатать требуемые для обновления целевых файлов команды, но не выполнять их. —t Обновить даты модификации целевых файлов, не выполняя никаких команд. —s Выполнить операции без вывода информационных сообщений. man — распечатать руководство MAN(l) man [ том ] заголовок ... Команда man форматирует и выводит заданный набор описа- ний из руководства по системе UNIX. Если задан том, man ищет заданные заголовки в этом томе. Том задается цифрой — номером тома (например, 3) и, возможно, уточняется одной бук- вой (например, ЗМ означает математическую подпрограмму из третьего тома). Если том опущен, man просматривает все тома
Приложение 1. Команды 331 руководства и выводит первое найденное описание с заданным заголовком (если такое есть). Предпочтение отдается описаниям команд по сравнению с описанием подпрограмм из системных биб- лиотек. mesg — разрешить или запретить передачу сообщений на тер- минал MESG(l) mesg [ n ] [ у ] Команда mesg с параметром п («нет») запрещает передачу сообщений через команду write(l) на данный терминал путем отмены права записи на этот терминал для всех, кроме самого пользователя. Команда mesg с параметром у («да») восстанавли- вает это право. Команда mesg без параметров сообщает текущее состояние терминала, не меняя его. mkdir — создать оглавление MKDIR(l) mkdir имяогл ... Команда mkdir создает указанные оглавления с полномочия- ми, определяемыми маской пользователя umask. Автоматически создаются стандартные ссылки . (на само это оглавление) и .. (на вышестоящее, родительское оглавление). Для выполнения команды mkdir необходимо иметь право на запись в родительское оглавление. mv — пересылка или переименование файлов MV(1) mv файл1 файл2 mv файл ... оглавление Команда mv пересылает (переименовывает) файл1 в файл2. Если файл2 уже существует, он предварительно исключается. Если право записи в файл2 отсутствует, mv выводит полномочия этого файла (см. chmod(2)) и считывает одну строку из стандарт- ного файла ввода. Если эта строка начинается с буквы у (что означает «да»), то пересылка (переименование) выполняется; иначе mv заканчивает работу. Команда mv во второй форме пе- ресылает один или несколько файлов в заданное оглавление, сохраняя их имена. Некоторые версии этой команды позволяют переименовывать оглавления. Команда mv отказывается пересылать файл в себя.
332 Приложение 1. Команды newgrp — войти в новую группу NEWGRP(l) newgrp группа Команда newgrp изменяет идентификацию группы обративше- гося к ней процесса по аналогии с командой login(l). Идентифи- кация пользователя и текущее оглавление остаются неизменны- ми, но права доступа к файлам вычисляются согласно новому идентификатору группы. Команда newgrp является встроенной: программа-оболочка выполняет ее непосредственно без образования нового процесса. nice — выполнить команду с низким приоритетом NICE(l) nice [ — число ] команда [ параметры ] Команда nice позволяет выполнить некоторую команду с по- ниженным приоритетом. Если задан параметр число, значение приоритета увеличивается на эту величину (максимум на 20). Чем больше значение приоритета, тем меньше реальней приори- тет. По умолчанию берется число 10. Суперпользователь может выполнять команды с более вы- соким реальным приоритетом, чем обычно, задавая отрицатель- ный приоритет, например------10. пт — распечатать таблицу символов NM(1) nm [ опция ] [ файл ... ] Команда пт печатает список имен (таблицу символов) для каждого объектного файла из списка параметров. Если параметр является библиотекой, такой список генерируется для каждого объектного файла из библиотеки. Если не задано ни одного па- раметра-файла, выводится список имен для файла a.out. Перед именем каждого символа выводятся его значение (про- бел, если символ не определен) и одна из букв: U (не определен), А (абсолютный), Т (символ программного сегмента), D (символ сегмента данных), В (символ сегмента bss), С (символ общей области), f (имя файла) или знак минус для элементов таблицы символов, предназначенных для отладчика sdb (см. опцию —а ниже). Для локальных (не внешних) символов типы задаются малыми буквами. Список упорядочивается в алфавитном по- рядке.
Приложение 1. Команды 333 Опции —а Распечатать все символы. Обычно символы, предна- значенные для sdb(l), не печатаются. —g Распечатать только глобальные (внешние) символы. —п Упорядочить список по адресам, а не по алфавиту. —о Выводить имя файла или элемента библиотеки не один раз, а перед каждой строкой. —р Напечатать символы в том порядке, в котором они встречаются в таблице символов, без переупорядочи- вания. —г Упорядочить в обратном порядке. — -и Распечатать только неопределенные символы. nohup — выполнить команду с защитой от прерываний NOHUP(l) nohup команда [ параметры ] Команда nohup позволяет защитить запускаемую команду от разрыва связи с управляющим терминалом и от сигналов за- вершения, вводимых с управляющего терминала. Команду nohup следует вызывать из фоновой оболочки, чтобы предотвратить не- желательные эффекты (прерывания, пропадание ввода), возни- кающие при входе в систему с того же терминала нового пользо- вателя. od — восьмеричный дамп OD(1) od [ опция ] [ файл ] Команда od распечатывает содержимое файла в одном или в нескольких форматах, задаваемых первым параметром. Если первый параметр опущен, подразумевается —о. Параметр файл указывает файл, содержимое которого тре- буется распечатать. Если этот параметр не задан, используется файл стандартного ввода. Опции — -Ь Напечатать каждый байт в восьмеричном виде. — с Напечатать каждый байт в коде ASCII. Некоторые неграфические литеры выводятся в виде комбинаций, используемых для их представления в языке С; ос- тальные — в виде восьмеричного числа из трех цифр. — d Напечатать каждое короткое слово (16 бит) в десятич- ном виде.
334 Приложение 1. Команды — о Напечатать каждое короткое слово (16 бит) в восьме- ричном виде. — х Напечатать каждое короткое слово (16 бит) в шестнад- цатеричном виде. — D Напечатать каждое длинное слово (32 бита) в десятич- ном виде. — О Напечатать каждое длинное слово (32 бита) в восьме- ричном виде. — X Напечатать каждое длинное слово (32 бита) в шест- надцатеричном виде. passwd — изменить пароль для входа в систему PASSWD(l) passwd [ имя ] Эта команда изменяет (или устанавливает) пароль, защищаю- щий регистрационное имя пользователя (по умолчанию — ваше собственное регистрационное имя). Программа запрашивает сначала старый пароль, затем — новый. Пользователь должен ввести оба пароля. Новый пароль требуется ввести дважды, чтобы предупредить возможную ошиб- ку. Новый пароль должен состоять по крайней мере из четырех литер, если используется достаточно широкий набор литер, и по крайней мере из шести литер, если используются литеры од- ного регистра. Эти правила ослабляются, если вы проявляете упорство. Пароль может изменить только владелец регистрационного имени или суперпользователь; владелец должен подтвердить старый пароль. рг — распечатать файл PR(1) рг [ опция ] ... ( файл ] ... Команда рг печатает листинг одного или нескольких файлов. Листинг состоит из страниц, в заголовке которых содержатся дата, имя файла (или заданный текст) и номер страницы. Если ни одного параметра-файла не задано, распечатывается файл стандартного ввода. Во время работы рг передача сообщений при помощи команды write(l) на данный терминал запрещена. Опции Опции применяются ко всем последующим файлам, но их можно переустанавливать, задавая между файлами.
Приложение 1. Команды 335 — и Выполнять вывод в п колонок. +п Пронумеровать страницы, начиная с номера п. — h Использовать следующий параметр в качестве заголовка страниц. — w п Установить ширину страницы равной п литерам вместо 72 по умолчанию. Используется при выводе текста в несколько колонок. — f Использовать для перехода на новую страницу ли- теры перевода формата вместо литер новой строки. Предполагается, что перевод формата пропускает две пустые строки в начале страницы. (Таким об- разом, эта опция не влияет на действительную дли- ну страницы.) — 1 п Установить длину страницы равной п строкам вместо 66 по умолчанию. — t Не выводить пятистрочные «шапку» и «концевик», обычно сопровождающие каждую страницу. — -s с Отделять колонки одной литерой с вместо подходя- щего количества пробелов. Если с опущено, ис- пользуется литера табуляции. — m Печатать все файлы одновременно, каждый в своей колонке. prof — выдать результаты профилирования PROF(l) prof [ опция ] [ a.out [ mon.out ... ] ] Команда prof интерпретирует файл, сгенерированный под- программой monitor (3). В стандартном режиме считывается таб- лица символов указанного объектного файла (по умолчанию a.out) и сопоставляется с профильным файлом (по умолчанию mon.out). Для каждого внешнего символа печатаются процент времени, затраченного на выполнение участка программы от этого символа до следующего (печать выполняется в порядке убывания этой величины), а также количество обращений к дан- ной подпрограмме и время (в миллисекундах), затраченное в среднем на каждый вызов. Если задано несколько профильных файлов, выдается объединение этих профилей. Для того чтобы количество обращений к подпрограмме соот- ветствовало действительности, при компиляции файла, содержа- щего эту подпрограмму, в командах сс и f77 следует задавать опцию —р. Эта опция обеспечивает также автоматическое по- рождение профильного файла.
336 Приложение 1. Команды Опции — а Выдать информацию о всех символах, а не только о внешних. — 1 Упорядочить результаты по значению (адресу) символов. — п Упорядочить результаты по количеству обращений. — s Сгенерировать объединенный профильный файл и поместить его в топ.sum. Эта опция полезна, только когда задается более одного профильного файла. —z Включить в выводимые результаты также и неис- пользовавшиеся подпрограммы (имеющие нулевые значения счетчика обращений и накопленного времени). ps — состояние процессов PS(1) ps [ опция ] Команда ps выдает информацию о процессах. По умолчанию ps печатает только ваши процессы; задание опции а вызывает печать процессов и других пользователей; если задана опция х, то печатаются также и процессы, не имеющие управляющих тер- миналов. Для каждого процесса во всех форматах вывода команды ps выводятся следующие сведения: PID — идентификатор про- цесса, ТТ — управляющий терминал процесса, TIME — время центрального процессора, использованное данным процессом (сюда входит время, затраченное на выполнение как программ пользователя, так и системных функций), STAT — состояние процесса и COMMAND — команда, выполняемая процессом в данный момент. Состояние процесса представляется последова- тельностью из четырех букв, например RWNA. Первая буква указывает, готов или не готов процесс к выполнению: R — про- цесс готов к выполнению, Т — остановлен, D — ожидание окон- чания обмена с диском (или другие краткосрочные задержки), S — процесс отложен не более чем на 20 секунд, I — процесс отложен более чем на 20 секунд. Вторая буква указывает, отка- чен ли процесс на диск или нет: W — процесс откачен, пробел — процесс находится в основной памяти. Опции а Выдать информацию о всех процессах, связанных с терминалами (обычно выводятся только процессы данного пользователя).
Приложение 1. Команды 337 g Наряду с параметрами команды напечатать и ее среду. Перечислить все процессы. Без этой опции ps распечатывает только процессы, представляющие интерес. Считается, что процесс не представляет ин- тереса, если он является главой группы процессов. Это условие позволяет исключать из рассмотрения процессы, в рамках которых выполняются команд- ные интерпретаторы верхнего уровня и процессы, ожидающие появления пользователей на свобод- ных терминалах. 1 Выдавать информацию в «длинном» формате, со- держащем поля PPID,CP, PRI, NI, ADDR, SIZE, RSS и WCHAN, описание которых приводится ниже. х Выдать информацию и о процессах, не связанных с терминалами. * Если задан номер процесса, обозначенный здесь зна- ком выдать информацию только об этом про- цессе. Эта опция должна задаваться последней. Порожденный процесс помечается меткой <defunct> («за- кончившийся»), если он завершился; но его родительский про- цесс еще не ждет его завершения; процесс, заблокированный при попытке завершиться, помечается меткой <exiting> («за- вершающийся»). Что касается имени файла и параметров, задан- ных при создании процесса, то команда ps отгадывает их путем анализа содержимого оперативной памяти или откаченного образа процесса. Такой метод по своему существу не является надежным: в любой момент процесс имеет право разрушить эту информацию. Поэтому нельзя целиком полагаться на имена, выводимые ps. ptx — циклический указатель РТХ(1) ptx [ ОПЦИЯ [ вход [ выход ] ] Команда ptx порождает циклический указатель для файла вход и помещает его в файл выход (по умолчанию используются стандартные файлы ввода и вывода). Действие выполняется в три этапа. На первом этапе делаются перестановки. Для каж- дого ключевого слова во входном файле порождается одна стро- ка; эта строка циклически сдвигается таким образом, чтобы клю- чевое слово попало в начало строки. Полученный файл сорти- руется. Наконец, отсортированные строки циклически сдви- гаются так, что ключевое слово попадает в середину страницы. Вывод команды ptx имеет вид
338 Приложение 1. Команды .хх "конец" "текст до" "ключевое слово и текст после" "начало" где макроопределение .хх может быть описано пользователем в nroff или troff(1). Поля "текст до" и "ключевое слово и текст после" представляют собой соответствующие части строки, когда клю- чевое слово расположено в середине страницы (при этом учиты- вается заданная длина выходной строки). Поля "конец" и "на- чало", по крайней мере одно из которых является пустой цепоч- кой"", представляют собой не поместившиеся в основных полях кусочки строки, достаточно маленькие, для того чтобы их можно было поместить в противоположный конец строки. Если часть исходного текста приходится отбрасывать, это место помечается литерой /. Опции —f —t —w —g —о —i —b —r He различать при сортировке прописные и строчные буквы. Подготовить вывод для фотонаборного уст- ройства. Подразумеваемая длина строки — 100 литер. п В качестве длины выходной строки исполь- зовать следующий параметр — п. Подразу- меваемая длина строки — 72 литеры. п I Использовать следующий параметр, /г, в ка- честве минимального количества литер, от- водимых под промежутки между четырьмя полями выводимой строки. Подразумевае- мая длина промежутка — 3 литеры. только Использовать в качестве ключевых слов только слова из файла только. игнор Не использовать в качестве ключевых слов слова из файла игнор. Если опции —i и —о опущены, то в качестве файла игнорируе- мых слов для —i используется файл /usr//lib/eign. разделители Для разделения слов использовать литеры из файла разделители. В любом случае ли- терами-разделителями всегда также явля- ются пробел, табуляция и новая строка. Считать первые отличные от пробелов ли- теры каждой входной строки ее ссылочным идентификатором (наподобие номера стра- ницы или названия главы), не входящим в собственно текст строки. Помещать этот
Приложение 1. Команды 339 идентификатор в каждую выходную строку в качестве пятого поля. pubindex — создать инвертированный указатель для файла, содержащего библиографию PUBI NDEX(l) pubindex [ файл ] ... Команда pubindex создает для указанных файлов хешируемый инвертируемый указатель, используемый командой refer(l). Фай- лы содержат библиографические ссылки, разделенные пустыми строками. Ссылка представляет собой последовательность строк, содержащих поля библиографической информации. Каждое поле начинается со строки, первой литерой в которой является %, за которым следуют ключевая буква, пробел и далее — содержимое поля, продолжающееся до следующей строки, начинающейся с литеры %. pwd — имя рабочего оглавления PWD(l) pwd Команда pwd печатает составное имя рабочего (текущего) оглавления. ranlib — преобразование архива в библиотеку с произвольным доступом RA NLI В(1) ranlib архив ... Команда ranlib преобразует каждый архив к формату, уско- ряющему работу загрузчика. Для этого в начало архива добав- ляется оглавление с именем _.SYMDEF. Для преобразования архива ranlib использует команду аг(1), поэтому в файловой сис- теме, содержащей текущее оглавление, должно быть в наличии достаточное количество пространства под временное пользование. refer, lookbib — найти и вставить в документ ссылки на лите- ратуру REFER(l) refer [ опция ] ... lookbib [ файл ] ... Команда lookbib считывает ключевые слова из файла стан- дартного ввода и исследует библиографическую базу данных в поисках ссылок, которые содержат эти ключевые слова в полях,
340 Приложение 1. Команды задающих заглавие работы, фамилии авторов, название журнала и т. д. Найденные ссылки выдаются в файл стандартного вывода. В качестве разделителей между запросами используются пустые строки. Команда refer представляет собой препроцессор к nroff и troff(1), который ищет и формирует библиографические ссылки. Входные файлы (по умолчанию — файл стандартного ввода) копируются в стандартный вывод, за исключением строк, распо- ложенных между запросами .[ и .]. Предполагается, что эти строки содержат ключевые слова (как и в команде lookbib); они заменяются данными, взятыми из библиографической базы дан- ных. Пользователь может отменять поиск ссылки, изменять значения полей или добавлять новые поля. В любом случае ссылочная информация присваивается некоторому набору troff- цепочек. Ссылки в окончательном виде печатаются из этих цепо- чек при помощи макропакетов типа ms. На место ссылки в тексте помещается флаг. По умолчанию ссылки осуществляются по номерам. Опции —а г Поменять местами имена и фамилии первых г авторов (Jones, J. А. вместо J. A. Jones). Если г опущено, то меняются местами имена и фамилии всех авторов. —b «Голый» режим. Не помещать флаги на место ссылок в тексте (ни номера, ни метки). —с цепочка Печатать прописными буквами поля, ключевые буквы которых заданы в цепочке. —е Вместо того чтобы оставлять ссылки в тех мес- тах, где они встречаются, накапливать их, пока не встретится слово вида $LIST$. Записать в это место все накопленные до сих пор ссылки. Ссылка на один и тот же источник выводится один раз. —к х Вместо нумерации ссылок использовать метки, заданные в строке ссылочных данных, начинаю- щейся с %х; подразумеваемым значением для х является L. —1 т.п Вместо нумерации ссылок использовать метки, составленные из фамилии первого автора и года публикации. Использовать только т первых букв фамилии автора и п последних цифр года. Если либо т, либо п опущены, используются полные фамилии или даты. *—р Использовать в качестве библиографического
Приложение 1. Команды 341 файла для поиска файл, заданный следующим параметром. Подразумеваемый файл просматри- вается последним. —и Не выполнять поиск в подразумеваемом файле. —s ключи Упорядочить ссылки по значениям полей, клю- чевые буквы которых заданы в цепочке ключи. Соответствующим образом скорректировать но- мера ссылок в тексте. Эта опция устанавливает опцию —е. За ключевыми буквами в цепочке клю- чи может следовать число, указывающее, какое ко- личество полей данного типа следует использо- вать при сортировке; + означает максимальное число полей. Подразумеваемым значением яв- ляется AD, т. е. упорядочение по фамилии пер- вого автора, а при одинаковых фамилиях — по дате. Для упорядочения сначала по фамилиям всех авторов, а потом по заглавию следует ис- пользовать —sA+T. Для того чтобы использовать свои собственные библиографи- ческие ссылки, поместите их в файл в формате, описанном в разд. 7.3.5. Поиск ссылок будет выполняться быстрее, если этот файл обработать командой pubindex(l); ошибка при создании указателя приведет к линейному поиску. rm, rmdir— уничтожить (ссылку на) файл RM(1) rm [ опция ] файл ... rmdir огл ... Команда rm исключает из оглавления одну или несколько ссылок на файлы. Если исключаемая ссылка была последней ссылкой на файл, файл уничтожается. Для исключения файла из оглавления необходимо иметь право на запись в это оглавление, но не требуется права ни на чтение, ни на запись в сам файл. Если право на запись в файл отсутствует, а стандартным файлом ввода является терминал, на него выводятся полномочия файла и считывается одна строка. Если эта строка начинается с символа у (что означает «да»), файл уничтожается, иначе — сохраняется. Если задана опция —f, вопросы не задаются и сообщения не выводятся. Если указанный файл является оглавлением, то кроме слу- чая, когда задана опция —г, выводится сообщение об ошибке. Если задана опция —г, rm рекурсивно уничтожает содержимое всего указанного оглавления и его само.
342 Приложение 1. Команды Если задана опция —i, rm спрашивает про каждый файл, требуется ли его исключить, и про каждое оглавление (если за- дана опция —г), требуется ли его просматривать. Пустая опция (знак минус) указывает, что все следующие параметры следует считать именами файлов. Это позволяет зада- вать имена файлов, начинающиеся со знака минус. Команда rmdir исключает заданные оглавления. Эти оглав- ления должны быть пустыми. sdb — символьный отладчик SDB(1> sdb [ объект [ образ [ оглавление ] ] ] Команда sdb представляет собой символьный отладчик, пред- назначенный для отладки программ на языках С, Паскаль и Фортран 77. Его можно использовать для анализа объектных файлов и для выполнения программ под управлением пользо- вателя. Параметр объект — это файл с готовой программой, которая должна быть скомпилирована с опцией —g (отладка); подразуме- ваемым значением объекта является файл a.out. Предполагается, что файл образ содержит образ памяти, полученный при выпол- нении данного объекта; подразумеваемым образом является файл core. В любой момент времени имеется текущая строка и текущий файл. Если образ существует, то изначально текущими являются строка и файл, содержащие оператор исходного текста програм- мы, на котором было остановлено исполнение процесса. В про- тивном случае текущим файлом становится файл, содержащий подпрограмму main, а текущей строкой — первая строка этой подпрограммы. Текущие строку и файл можно изменять, исполь- зуя запросы анализа содержимого исходных файлов. Имена переменных записываются в точности в том же виде, в каком они выглядят в языках С, Паскаль и Фортран 77. До- ступ к локальным переменным процедуры осуществляется при помощи записи процедура:переменная. Если имя процедуры опущено, подразумевается процедура, содержащая текущую строку. Можно также ссылаться на элементы структуры в виде переменная.элемент, обращаться к элементам структуры через указатели посредством переменная—>элемент и выбирать эле- менты массива посредством переменная[номер]. Можно исполь- зовать и комбинации из этих выражений. Можно также указывать переменную по ее адресу. Допускает- ся использование всех видов целых констант, принятых в язы- ке С, поэтому адреса могут задаваться в десятичном, восьмерич- ном или шестнадцатеричном виде.
Приложение 1. Команды 343 Ссылки на номера строк в исходной программе делаются в виде имя-файла: номер или процедура:номер. В обоих случаях номер задается относительно начала соответствующего файла. Если опущен номер, подразумевается первая строка указанной процедуры или файла. Запросы анализа состояния данных t Распечатать трассировку стека (имена функций, вызванных последними) для завершившейся или остановленной программы. Т Распечатать первую строку из трассировки стека. переменная//т Распечатать значение переменной в соответствии с длиной I и форматом т. Если I и т опущены, от- ладчик выбирает длину и формат в соответствии с описанным в программе типом этой переменной. Спецификациями длины являются: b Один байт. h Два байта (короткое слово). 1 Четыре байта (длинное слово), число Длина цепочки для форматов s и а (см. ниже). Допустимыми значениями для m являются: с Символ. d Десятичное целое. и Десятичное целое без знака. о Восьмеричное целое. х Шестнадцатеричное целое. f Число с плавающей точкой обычной точности (32 бита). g Число с плавающей точкой двойной точности (64 бита). s В предположении, что переменная является указателем на цепочку символов, распеча- тать символы из этой цепочки вплоть до сим- вола «пусто». а Распечатать символы, начиная с символа, ад- рес которого совпадает с адресом данной пере- менной, вплоть до символа «пусто». р Указатель на процедуру. Спецификации длины действуют только с формата- ми d, и, о и х. Если задан один из этих форматов, а 1 опущено, в качестве подразумеваемой длины ис- пользуется длина слова на данной ЭВМ (4 для VAX
344 Приложение 1. Команды 11/780). Последнюю переменную можно распеча- тать снова запросом ./. В именах процедур и переменных можно использо- вать метасимволы * и ? языка-оболочки sh(l). Та- ким образом, в ограниченном виде предоставляются средства сопоставления с образцами. Если имя процедуры опущено, сопоставление выполняется с именами как локальных для текущей процедуры переменных, так и глобальных (в Фортране 77 —об- щих) переменных; однако если имя процедуры ука- зано, то сопоставление выполняется только с име- нами переменных, локальных для это?! процедуры. Для сопоставления только с именами глобальных переменных (в Фортране 77 — переменных из не- именованной общей области) используется запись :образец. Для программ на Фортране 77 вместо имени процедуры можно задавать имя общего блока. переменная^ 1т номер-строки=1т число=/т Распечатать адрес переменной, номер строки ис- ходного текста или значение числа в указанном формате. Если формат не задан, подразумевается 1х. Последний вариант запроса предоставляет удоб- ный способ преобразования целых чисел из деся- тичного, восьмеричного, шестнадцатеричного вида в другой. переменная! значение Присвоить переменной заданное значение. Значе- нием может быть число, символьная константа или переменная. Кроме того, если переменная имеет тип с плавающей точкой (обычной или двойной точности), значением может быть константа с пла- вающей точкой. Запросы анализа содержимого исходных файлов е процедура е имя-файла.с Сделать текущим файлом файл, содержащий ука- занную процедуру, или файл с заданным именем. Сделать текущей строкой первую строку указан- ной процедуры или файла. Предполагается, что все исходные файлы находятся в оглавлении оглавление. Подразумеваемым оглавлением является
Приложение 1. Команды 345 рабочее оглавление. Если имя процедуры или файла не задано, выдаются имена текущей процедуры и файла. /регулярное выражение/ Поиск строки, содержащей цепочку литер, сопо- ставляющуюся с данным регулярным выражением. Поиск выполняется в прямом направлении, начи- ная от текущей строки. Регулярные выражения описаны в разд. 8.1. Последнюю литеру / можно опускать. ?регулярное выражение? Поиск строки, содержащей цепочку литер, сопо- ставляющуюся с данным регулярным выражением. Поиск выполняется от текущей строки в обратном направлении. Последнюю литеру ? можно опускать. р Распечатать текущую строку. z Распечатать текущую и 9 следующих строк. Теку- щей станет последняя распечатанная строка. AD «Прокрутить». Распечатать следующие 10 строк. Текущей становится последняя распечатанная стро- ка. w Окно. Распечатать 10 строк вокруг текущей строки, номер Сделать текущей строку с заданным номером. Рас- печатать новую текущую строку. п+ Продвинуться вперед на п строк. Распечатать новую текущую строку. п— Продвинуться назад на п строк. Распечатать новую текущую строку. Запросы управления выполнением счетчик г параметры счетчик R Начать выполнение программы с заданными пара- метрами. Если в запросе г параметры не заданы, ис- пользуются параметры предыдущего запуска про- граммы, в то время как запрос R запускает про- грамму без параметров. Параметры, начинающиеся с <или>, вызывают переадресацию стандартного ввода и вывода соответственно. Если задан счетчик, он определяет количество контрольных точек, кото- рые будут проигнорированы. номер-строки с счетчик номер-строки С счетчик Продолжить выполнение после контрольной точки или прерывания. Если задан счетчик, он определяет
346 Приложение 1. Команды количество контрольных точек, которые будут про- игнорированы. По запросу С выполнение продол- жается с возбуждения сигнала, вызвавшего приос- тановку программы, а по запросу с этот сигнал иг- норируется. Если указан номер строки, на эту строку устанавливается временная контрольная точ- ка, и выполнение продолжается. Эта контрольная точка уничтожается после завершения выполнения команды. счетчик s Пошаговое выполнение. Выполнить несколько строк программы. Число строк задается счетчиком. Если счетчик не задан, выполняется одна строка. счетчик S Пошаговое выполнение, но шагом считается вызов подпрограммы. к Уничтожить процесс, выполняющий отлаживаемую программу. процедура(парам1, парам2,...) процедура(парам1, парам2,...)/т Выполнить заданную процедуру с заданными пара- метрами. Параметрами могут быть целые, литерные и текстовые константы или имена переменных, до- ступных в текущей процедуре. Запрос во втором варианте печатает возвращаемое процедурой зна- чение согласно формату т. Если формат не задан, подразумевается d. номер-строки b запросы Установить контрольную точку на заданную стро- ку. Если задано имя процедуры без номера строки (например, proc:), контрольная точка устанавли- вается на первую строку процедуры, даже если эта процедура не была скомпилирована с флагом отлад- ки. Если номер-строки не задан, контрольная точка устанавливается на текущую строку. Если запросыне заданы, то непосредственно перед контрольной точ- кой выполнение программы приостанавливается и управление передается отладчику. В противном случае при прохождении контрольной точки вы- полняются заданные запросы, и продолжается вы- полнение программы. Если задано несколько за- просов, они разделяются точкой с запятой. номер-строки d Удалить контрольную точку на данной строке. Если номер-строки не задан, то контрольные точки уда- ляются в интерактивном режиме. Печатается место- нахождение каждой контрольной точки и считы- вается строка из файла стандартного ввода. Если
Приложение 1. Команды 347 эта строка начинается с у или d, то данная контроль- ная точка удаляется. В Распечатать список контрольных точек, установлен- ных на данный момент. D Удалить все контрольные точки. 1 Распечатать последнюю выполненную строку. номер-строки а Оповещение. Если номер-строки имеет вид про- цедура: номер, по этому запросу фактически выпол- няется запрос номер-строки b 1. Если номер-строки имеет вид процедура:, выполняется запрос процедура: b Т Прочие запросы '.команда Указанная команда интерпретируется программой- оболочкой sh (1). возврат каретки Если по предыдущему запросу была распечатана строка исходного текста программы, то текущей строкой становится следующая строка, и эта стро- ка печатается. Если предыдущим запросом было выведено содержимое некоторой ячейки памяти, то выводится содержимое следующей ячейки памяти. " Распечатать данную цепочку литер. q Выйти из отладчика. sed — пакетный редактор SED(l) sed [ —n ] [ —е прог ] [ —f прогфайл ] [ файл ] ... Редактор sed копирует указанные файлы (по умолчанию — файл стандартного ввода) в файл стандартного вывода, выполняя при этом редактирующие действия согласно цепочке запросов прог. Если задана опция —f, то запросы берутся из файла прог- файл. Можно задавать несколько опций —е и —f. Если задана ровно одна опция —е и ни одной опции —f, флаг —е можно опустить. Опция —п отменяет подразумеваемый вывод. Каждый запрос редактирования размещается на отдельной строке и имеет следующий вид: [адрес [,адрес] ] функция [аргументы] В обычном режиме работы sed в цикле копирует одну строку входного файла в рабочий буфер (только если в нем ничего не осталось после запроса D); применяет по порядку все запросы, адреса которых соответствуют содержимому рабочего буфера;
348 Приложение 1. Команды по исчерпанию списка запросов копирует содержимое рабочего буфера в файл стандартного вывода (за исключением случая, если задан флаг —п) и уничтожает содержимое рабочего буфера. Адрес представляет собой либо десятичное число, задающее номер входной строки (для нескольких входных файлов нумера- ция сквозная), либо $, что означает последнюю входную строку, либо контекстный адрес /регулярное выражение/ в виде, описан- ном в разд. 8.1, но со следующей модификацией: комбинация \п сопоставляется с литерой новой строки в рабочем файле. Запрос без адреса применяется при любом содержимом рабо- чего буфера. Запрос с одним адресом применяется, когда этот адрес соответствует содержимому рабочего буфера. Запрос с двумя адресами применяется к диапазону последо- вательных значений рабочего буфера начиная с того момента, когда его содержимое сопоставляется с первым адресом, и до тех пор (включительно), пока оно не сопоставится со вторым ад- ресом. (Если второй адрес — число, меньшее или равное номеру первой строки диапазона, запрос применяется только к этой строке.) Далее процесс повторяется: опять выполняется сопо- ставление с первым адресом и т. д. Используя функцию отрицания ! (см. ниже), запросы редак- тирования можно применять только к тем из последовательных значений рабочего буфера, которые не входят во множество, определяемое адресами. Параметр, обозначенный текст, состоит из одной или несколь- ких строк, все из которых, кроме последней, оканчиваются лите- рой \, чтобы скрыть литеру новой строки. Литеры \ в тексте трактуются так же, как и в заменяющей цепочке запроса s, и могут использоваться для сохранения начальных пробелов и табуляций, которые отбрасываются в каждой строке файла за- просов. Параметры r-файл и w-файл должны быть последними в стро- ке, и им должен предшествовать ровно один пробел. Каждый w-файл создается перед началом редактирования. Можно задать до 10 различных w-файлов. а\ текст . Добавить текст. Поместить текст в выходной файл перед считыванием следующей входной строки. b метка Перейти на запрос : с указанной меткой. Если метка не задана, перейти на конец файла запросов. текст Заменить. Исключить содержимое рабочего буфе- ра. Если ни одного адреса не задано или задан
Приложение 1. Команды 349 один адрес, а также в конце двухадресного диапа- зона поместить текст в выходной файл. Начать следующую итерацию цикла. d Исключить содержимое рабочего буфера. Начать следующую итерацию цикла. D Исключить начальный сегмент рабочего буфера (до первой литеры новой строки включительно). На- чать следующую итерацию цикла. g Заменить содержимое рабочего буфера содержимым вспомогательного буфера. G Добавить к содержимому рабочего буфера содер- жимое вспомогательного буфера. h Заменить содержимое вспомогательного буфера со- держимым рабочего буфера. Н Добавить к содержимому вспомогательного буфера содержимое рабочего буфера. текст Вставить. Поместить текст в файл стандартного вывода. п Скопировать содержимое рабочего буфера в файл стандартного вывода. Заменить содержимое рабо- чего буфера следующей входной строкой. N Добавить к содержимому рабочего буфера следую- щую входную строку (вместе с литерой новой строки). Номер текущей строки изменяется. р Печать. Скопировать содержимое рабочего буфера в файл стандартного вывода. Р Скопировать начальный сегмент рабочего буфера (до первой литеры новой строки включительно) в файл стандартного вывода. q Выход. Перейти на конец файла запросов. Не начи- нать новую итерацию цикла. г г-файл Считать содержимое файла г-файл. Поместить его в выходной файл перед чтением следующей входной строки. s /регулярное выражение/замена/флаги Заменить в рабочем буфере вхождения регулярного выражения на цепочку замена. Как и в редакторе ed, вместо / можно использовать любую другую ли- теру. Флаги представляют собой последователь- ность из нуля или более конструкций вида: g Глобальная замена. Заменить все непересе- кающиеся вхождения регулярного выраже- ния, а не только первое из них. р Распечатать содержимое рабочего буфера^ если замена выполнена.
350 Приложение 1. Команды w w-файл Записать. Добавить содержимое ра- бочего буфера в конец файла w-файл. t метка Проверить условия. Перейти на запрос : с указан- ной меткой, если с момента последнего чтения вход- ной строки или выполнения запроса t были выпол- нены какие-либо замены. Если метка не задана, перейти на конец файла запросов. w w-файл Записать. Если была выполнена замена, добавить содержимое рабочего буфера в конец файла w-файл. х Поменять местами содержимое рабочего и вспомо- гательного буферов. у/цепочка1/цепочка2 Преобразовать символы. Заменить все вхождения символов из цепочки! на соответствующие символы из цепочки2. Длины цепочки 1 и цепочки2 должны быть одинаковыми. 1 функция «Не». Применить функцию (или группу функций, если функция имеет вид {...}) только к строкам, не входящим во множество строк, определяемое адре- сом (адресами). : метка По этому запросу ничего не происходит. Он задает метку перехода, используемую в запросах b и t = Поместить в файл стандартного вывода в виде от- дельной строки текущий номер строки. { Выполнить последующие запросы вплоть до пар- ной скобки }, только если содержимое рабочего буфера соответствует заданным адресам. Пустой запрос игнорируется. sh — интерпретатор командного языка SH(1) sh [ опции ] [ парам ] ... Интерпретатор командного языка программирования. Вы- полняет команды, читаемые либо с терминала, либо из файла. Если первой литерой нулевого параметра является знак ми- нус, считываются команды из файла $НОМЕ/.profile, если такой файл существует. Далее считываются команды из стандартного ввода. Другие флаги описаны в гл. 4 вместе о командой set. Опции Приведенные ниже флаги интерпретируются программой-обо- лочкой при ее вызове.
Приложение 1. Команды 351 —с s Если задан флаг —с, то считываются и выполня- ются команды из цепочки s. —s Если задан флаг —s или же в команде нет ни одного параметра-файла, команды считываются из файла стандартного ввода. Вывод программы-оболочки записывается в файл с дескриптором 2. —-i Если задан флаг —i или если ввод и вывод оболоч- ки связаны с терминалом (это определяется с по- мощью системной функции gtty), оболочка является интерактивной. В этом случае сигнал завершения игнорируется (так что команда kill 0 не вызовет прекращения работы интерактивной оболочки), а сигнал прерывания перехватывается и игнори- руется (поэтому выполнение системной функции ожидания wait может быть прервано). Сигнал вы- хода игнорируется программой-оболочкой во всех случаях. size — определить размер объектного модуля S1ZE(1) size [ объектный-модуль ... ] Команда size для каждого параметра — объектного модуля печатает (в десятичном виде) количество байтов, занимаемых программным сегментом, сегментом данных, сегментом bss, и сум- марное количество байтов в шестнадцатеричном и десятичном виде. Если не задано ни одного параметра-файла, используется файл a.out. sleep — приостановить выполнение на заданный интервал времени SLEEP(l) sleep t Команда sleep приостанавливает выполнение процесса на t секунд. sort — сортировка и слияние файлов SORT(l) sort [ опции ] [ +поз1 [ —поз2 ] ] ... [ ОПЦИИ ] [ ИМЯ ] ... Команда sort считывает поименованные файлы, сортирует (упорядочивает) их и помещает результат в файл стандартного вывода. Имя — обозначает файл стандартного ввода. Если не задано ни одного имени входного файла, то сортируется файл стандартного ввода.
352 Приложение 1. Команды Подразумеваемым по умолчанию ключом сортировки является вся строка; подразумеваемым порядком сортировки является лексикографический порядок. Опции Следующие опции воздействуют на процесс сортировки глобаль- ным образом. Можно задавать одну или несколько этих опций. — b Игнорировать начальные пробелы и табуляции при сравнении полей. — d Порядок, используемый в словарях: в сравнении уча- ствуют только буквы, цифры и пробелы. — f Преобразовывать при сравнениях прописные буквы в строчные. —i Игнорировать при нечисловых сравнениях симво- лы, ASCII-коды которых лежат вне диапазона 040- 0176. —п Упорядочивать по арифметическому значению началь- ную числовую цепочку, состоящую из возможных про- белов, возможного знака минус и нуля или более цифр с возможной десятичной точкой. Опция — п автомати- чески устанавливает опцию —Ь. —г Изменить порядок сортировки на противоположный. —tx Использовать в качестве разделителя полей (табуля- ции) литеру х. Конструкция +поз1 — поз2 делает ключом сортировки поле, начинающееся с позиции поз1 и оканчивающееся непосредственно перед позицией поз2. Оба параметра поз! и поз2 имеют вид т.п; далее может следовать один или несколько флагов bdfinr. Число т задает количество полей, которое нужно пропустить от начала строки, а п задает количество литер, которое требуется пропус- тить в дополнение к этому. Если заданы флаги, они перебивают глобальные опции сортировки для этого ключа. Если действует опция Ь, то п отсчитывается от первого символа поля, отличного от пробела. Опцию b можно задавать независимо в поз2. Опущен- ное .п означает .0; опущенное —поз2 означает конец строки. Если задана опция —tx, то полями являются цепочки литер, разделенные литерой х; в противном случае поля представляют собой непустые цепочки литер, отличных от пробелов, разделен- ные пробелами (или табуляциями). Когда имеется несколько ключей сортировки, последующие ключи сравниваются, только если все предшествующие ключи равны. Строки, которые при выполнении операции сравнения оказались одинаковыми, упорядочиваются по всем значимым байтам.
Приложение 1, Команды 353 —с Проверить, что входной файл отсортирован согласно правилам, задающим порядок. Если файл упорядочен, ничего не выводится. —m Только слияние, входные файлы уже упорядочены. —о Следующий параметр является именем выходного файла, который будет использоваться вместо файла стандартного вывода. Этот файл может совпадать с одним из входных файлов. —Т Следующий параметр является именем оглавления, в котором следует создавать временные файлы. —и Сохранить только одну из множества равных строк. Игнорируемые байты и байты, не входящие в ключи, в этом сравнении на равенство не участвуют. spell — обнаружение орфографических ошибок SPELL(l) spell [ опция ] ... [ файл ] ... Команда spell выбирает слова из заданных документов и сверяет их правописание по встроенному списку правильных слов. Слова, которые не встречаются в этом списке и не являются производными от слов из этого списка (т. е. не образованы от них при помощи приставки или суффикса), выдаются в файл стан- дартного вывода. Если ни одного файла не задано, слова выби- раются из файла стандартного ввода. Команда spell игнорирует большинство troff, tbl и eqn(l) конструкций. Если задана опция —v, то печатаются все слова, которые не присутствуют буквально в таком виде в списке правильных слов. Приводятся вероятные способы образования этих слов от слов из списка. Если задана опция —Ь, то проверяется правописание, при- нятое в Англии. Предпочтение отдается написанию centre, colour, speciality, travelled и т. п. Кроме того, эта опция настаивает на употреблении суффикса —ise в словах типа standardise. Этало- нами американского и английского правописания являются сло- варь Фаулера и Оксфордский словарь. Под действием опции —х печатаются все возможные варианты словообразования со знаком = между ними. Список правильных слов составлен на основе многих источни- ков. Хотя он и менее систематизирован, чем обычный словарь, зато более подробен в отношении имен собственных и общепринятых технических терминов. Дополнение этого списка специальными терминами из области биологии, медицины и химии не вызывает проблем. 12 С. Баурн
354 Приложение 1. Команды strip — удалить таблицу символов и биты перемещения STRIP(l) strip файл ... Команда strip удаляет таблицу символов и биты перемещения, обычно присоединяемые к результирующим файлам ассемблером и загрузчиком. Это позволяет сэкономить пространство после завершения процесса отладки. Действие strip аналогично действию опции —s команды Id. stty — установить характеристики терминала STTY(l) stty [ ОПЦИЯ ... ] Команда stty устанавливает некоторые характеристики для терминала, выполняющего роль файла стандартного вывода. Ре- зультаты выполнения команды помещаются в файл диагностики. Команда stty без параметров выводит скорость терминала и ха- рактеристики, отличные от подразумеваемых. Если задан па- раметр all, то выдаются все обычно устанавливаемые характери- стики. Команда stty с параметром everything печатает всю извест- ную ей информацию. Опции even —even odd —odd raw —raw cooked cbrcak —cbreak —nl Выполнять контроль по четности при вводе. Не выполнять контроль по четности при вводе. Выполнять контроль по нечетности при вводе. Не выполнять контроль по нечетности при вводе. «Сырой» режим ввода (не выполнять никакой пер- вичной обработки вводимого текста (литер стира- ния, отмены, прерывания и т. п.); бит четности от- сылается назад). 4 Режим с первичной обработкой вводимого текста. Аналогично —raw. Разрешение считывать литеры при помощи read(2) по мере их ввода с клавиатуры; литеры стирания и отмены не интерпретируются, но в остальном вся первичная обработка текста (литера прерывания и т. п.) выполняется. Разрешение считывать литеры при помощи read(2) только после получения литеры новой строки. Интерпретировать возврат каретки как литеру новой строки и выводить комбинацию возврат каретки — перевод строки вместо литер возврата каретки и новой строки.
Приложение 1. Команды 355 nl Считать ограничителем строки только литеру но- вой строки. echo Отображать обратно на терминал каждую введен- ную литеру. —echo Не отображать вводимые литеры на терминале, lease Преобразовывать прописные буквы в строчные. —lease Не преобразовывать прописные буквы в строчные, tandem Выполнять управление потоком. Управление пото- ком состоит в том, что при вводе система посылает литеру приостановки в случае угрозы перепол- нения буфера ввода и литеру возобновления, когда она будет готова продолжить прием текста. —tandem Не выполнять управление потоком. —tabs При выводе заменять табуляции пробелами. tabs Сохранять литеры табуляции при выводе. ек Сделать литерами стирания и отмены # и @. erase с Сделать литерой стирания с (подразумевается =£). kill с Сделать литерой отмены с (подразумевается @). intr с Сделать литерой прерывания с (подразумевается del ИЛИ Л?). quit с Сделать литерой выхода с (подразумевается Л\). start с Сделать литерой возобновления вывода с (подразу- мевается AQ). stop с Сделать литерой приостановки вывода с (подразу- мевается AS). eof с Сделать признаком конца файла литеру с (подра- зумевается AD). brk с Сделать дополнительной литерой прерывания с (подразумеваемого значения нет). crO crl сг2 сгЗ Вид задержки для литеры возврата каретки (см. ioctl (2)). nIO nil nl2 n!3 Вид задержки для литеры перевода строки. tabO tabl tab2 tab3 Вид задержки для литеры табуляции. ffO ff 1 Вид задержки для литеры перевода формата. bsO bsl Вид задержки для литеры возврата на шаг. tty33 Установка соответствующих характеристик для терминала модели 33 фирмы Teletype. tty37 Установка соответствующих характеристик для терминала модели 37 фирмы Teletype. vt05 Установка соответствующих характеристик для терминала VT05 фирмы DEC. dec Установка характеристик, удобных для пользова- телей операционных систем фирмы DEC (сделать 12*
356 Приложение 1. Команды литерами стирания, отмены и прерывания Л?, AU и ЛС, decctlq и newcrt). tn300 Установка соответствующих характеристик для терминала TermiNet 300 фирмы General Electric. ti700 Установка соответствующих характеристик для терминалов серии 700 фирмы Texas Instruments. tek Установка подходящих характеристик для терми- нала 4014 фирмы Tektronix. О Немедленно разорвать связь по телефонному ка- налу. 50 75 ПО 134 150 200 300 600 1200 1800 2400 4800 9600 exta extb Установить (если это возможно) заданную скорость обмена с терминалом. style — анализ стиля документа STYLE(l) style [ —ml ] [ —mm ] [ опция ... ] файл ... Команда style анализирует внешние характеристики (стиль) документа. Она сообщает об уровне читаемости документа и пре- доставляет информацию о длине и структуре предложений, о дли- не и использовании слов, типе глаголов и способах построения предложений. Поскольку style перед просмотром текста обрабаты- вает его командой deroff, то входной файл следует включать форматирующие файлы заголовков. Подразумеваемым макро- пакетом является —ms, но его можно заменить, воспользовав- шись опцией —mm. Опцию —ml, заставляющуюderoff пропускать ссылки, следует использовать, если в документе содержится много списков, элементы которых не являются предложениями. Опции —а Распечатать все предложения вместе с информацией об их длине и уровне читаемости. —е Распечатать все предложения, начинающиеся с ввод- ных слов. —р Распечатать все предложения, содержащие гла- голы в пассивном залоге. —1 п Распечатать все предложения, имеющие длину, большую, чем п. —г п Распечатать все предложения, уровень читаемости которых выше п. *—Р Распечатать данные о том, какими частями речи являются слова в документе.
Приложение 1. Команды 357 tabs — установка табуляций для терминала TABS(l) tabs [ —n ] [ терминал ] Команда tabs устанавливает табуляции для различных тер- миналов. Распознаются различные имена типов терминалов; подразумеваемые установки подходят для большинства терми- налов, работающих со скоростью 300 бод. Если задан флаг —п, то левая граница в отличие от нормального случая не сдвигается. tail — распечатать хвостовую часть файла TAIL(l) tail [ ±n [Ibc] [fr] ] [ файл ] Команда tail копирует указанный файл в файл стандартного вывода, начиная с определенной позиции. Если файл не задан, используется файл стандартного ввода. Копирование начинается с позиции, расположенной на рас- стоянии +п от начала или —п от конца входного файла. Расстоя- ние п задается в строках, блоках или литерах в зависимости от задания опции 1, b или с. Если единица расстояния не задана, оно измеряется количеством строк. Если задана опция г, команда tail печатает строки с конца файла в обратном порядке. По умолчанию при задании опции г в обратном порядке печатается весь файл. Если задана опция f, то tail не завершает работу по концу файла, а переходит в состоя- ние ожидания и периодически пытается продолжить чтение в на- дежде, что файл за это время увеличился. tar — ведение архива на ленте TAR(l) tar [ ключ ] [ имя ... ] Команда tar позволяет сохранять файлы на ленте и восстанав- ливать их с ленты. Параметр ключ задает требуемое действие и представляет собой цепочку литер, содержащую самое большее одну функциональную букву и, возможно, один или несколько модификаторов. Остальные параметры команды являются име- нами файлов или оглавлений и определяют файлы, которые тре- буется сбросить на ленту или восстановить с ленты. Во всех случаях задание имени оглавления означает все поддерево файлов и подоглавлений, вершиной которого является данное оглав- ление. Функциональная часть ключа задается одной из следующих букв:
358 Приложение 1. Команды г Указанные файлы дозаписываются в конец ленты. Функция с влечет это действие. х Указанные файлы считываются с ленты. Если указан- ное имя соответствует оглавлению, содержимое кото- рого было записано на ленту, рекурсивно считывается все это оглавление. Владелец, время последней моди- фикации и полномочия файла сохраняются (если это возможно). Если не задано ни одного имени файла или оглавления, считывается все содержимое ленты. Замечание: если на ленте имелось несколько копий одного и того же файла, используется последняя. t Всякий раз, когда на ленте встречаются файлы с за- данными именами, эти имена распечатываются. Если ни одного имени файла не задано, распечатываются имена всех файлов на ленте. и Указанные файлы дозаписываются на ленту при ус- ловии, что либо их еще нет на ленте, либо они были модифицированы позднее последнего сброса на ленту. с Создать новый архив. Запись будет производиться с начала ленты, а не вслед за последним файлом. Эта команда влечет г. о При выводе tar обычно помещает в архив информацию о владельце и полномочиях оглавлений. р Эта опция восстанавливает файлы вместе с их преж- ними полномочиями, игнорируя текущее значение umask(2). Восстанавливаются также установка иден- тификации владельца при выполнении и прочая ин- формация, касающаяся суперпользователя. Кроме буквы, задающей функцию, в ключе могут использо- ваться следующие литеры-модификаторы: О,...,7 Этот модификатор определяет альтернативное ленто- протяжное устройство, на котором смонтирована тре- буемая лента (по умолчанию, используется устройст- во 0, работающее со скоростью 1600 бит/дюйм, кото- рое обычно имеет имя /dev/rmt8). v Обычно tar работает «молча». Если задана опция v (подробно), tar печатает имя каждого обрабатываемого файла, предваряя это имя буквой, соответствующей выполняемой функции. Если функцией является t, то помимо имени хранящегося на ленте файла выво- дятся дополнительные сведения о нем. w Прежде чем выполнить действие для какого-либо файла, напечатать это действие вместе с именем файла, а затем подождать подтверждения от пользователя. Если введенное слово начинается с буквы у («да»),
Приложение /. Команды 359 то действие выполняется; в противном случае ничего не делается. f В качестве архивного файла вместо /dev/rmt? исполь- зовать файл с именем, определяемым следующим пара- метром. Если имя файла задано как —, то tar будет в зависимости от действия считывать данные из файла стандартного ввода или записывать данные в файл стандартного вывода. Это позволяет использовать tar в качестве начального или конечного звена це- почки фильтров. Например, можно переписать иерар- хию оглавлений и файлов из одного места в другое командой cd fromdir; tar cf — . | (cd todir; tar xf —) Использовать следующий параметр в качестве коэф- фициента блокирования записей на ленте. Подразуме- вается 20 (максимум). Эту опцию следует применять только к «сырым» ленточным архивам (см. опцию f выше). При чтении ленты (ключевые буквы х и t) размер блока определяется автоматически. I Уведомить, если не удается разрешить все заданные ссылки на записанные на ленту файлы. Если этот модификатор не задан, никакого сообщения об ошибке не печатается. m Не восстанавливать время последней модификации файлов. Временем последней модификации станет время считывания файла с ленты. tbl — форматирование таблиц для nroff и troff TBL(l) tbl [ файл ] ... Команда tbl представляет собой препроцессор для формати- рования таблиц для nroff и troff(1). Входные файлы копируются в файл стандартного вывода, за исключением строк, заключенных между запросами .TS и .ТЕ. Предполагается, что эти строки со- держат описания таблиц; они подвергаются переформатиро- ванию. Если ни одного параметра не задано, препроцессор tbl счи- тывает файл стандартного ввода. Таким образом, его можно ис- пользовать в качестве фильтра. При совместном использовании с eqn или neqn сначала следует выполнить команду tbl для того, чтобы минимизировать объем данных, пересылаемых через транспортеры.
360 Приложение 1. Команды test—проверка условия TEST(l) test е Команда test вычисляет выражение е. Если его значением является истина, возвращается нулевой статус завершения; в противном случае возвращается ненулевой статус завершения. Если параметры не заданы, test возвращает ненулевой статус. Выражение е строится с использованием первичных выраже- ний следующего вида. Все флаги и знаки операций являются отдельными параметрами команды test. —г файл Файл существует, и его можно читать. —w файл Файл существует, и в него можно писать. —f файл Файл существует и не является оглавлением. —d файл Файл существует и является оглавлением. —s файл Файл существует и имеет отличную от нуля длину. —t [ дескр 1 Открытый файл с дескриптором дескр (по умол- чанию I) связан с терминалом. —z si Длина цепочки литер si равна нулю. —n si Длина цепочки литер si отлична от нуля. si = s2 Цепочки литер si и s2 совпадают. si != s2 Цепочки литер si и s2 не совпадают. si Цепочка литер si не является пустой. nl —eq n2 Целые nl и п2 алгебраически равны. Вместо —eq можно использовать любую из операций сравнения —-пе, —gt, —ge, -—It или —1е (не равно, больше, больше или равно, меньше, меньше или равно). Эти первичные выражения могут объединяться с использо- ванием следующих операций, где операция —а имеет более вы- сокий приоритет, чем —о. ! Унарное отрицание. —а Бинарное И. —о Бинарное ИЛИ. ( выражение ) Скобки для подвыражений. time — хронометраж команды Т1МЕ(1) time команда Заданная команда выполняется. После ее завершения time печатает астрономическое время работы команды и времена цент- рального процессора, использованные в процессе выполнения
Приложение 1, Команды. 361 команды системой и пользователем. Времена подсчитываются в секундах и направляются в поток стандартной диагностики. На PDP 11 время выполнения может зависеть от типа па- мяти, выделенной для выполнения команды. Время пользова- теля при выполнении команды в памяти типа MOS часто состав- ляет половину времени, затрачиваемого на выполнение той же команды в оперативной памяти. touch — обновить дату последней модификации файла TOUCH(l) touch [ —с 1 файл ... Команда touch пытается переустановить дату модификации для каждого файла. Это делается путем считывания одной литеры из файла и записи ее обратно. Если файл не существует, делается попытка создать его, за исключением случая, когда задана опция —с. tr — преобразование литер tr [ опция ] [ цепочка! [ цепочка2 ] ] TR(1) Команда tr копирует файл стандартного ввода в файл стан- дартного вывода, заменяя или удаляя при этом указанные лите- ры. Входные литеры, заданные в цепочке!, преобразуются в со- ответствующие литеры из цепочки2. Если цепочка2 короче це- почки!, она дополняется до длины цепочки! путем размножения последней литеры. Можно использовать любое сочетание опций —cds. Опции —с Использовать дополнение набора литер из цепочки! до множества литер с ASCII-кодами от 01 до 0377. —d Исключить все входные литеры, заданные в це- почке!. s Заменить в выходном файле все кратные вхождения литер из цепочки2 одной литерой. В обеих цепочках запись а—b означает диапазон литер от а до b в возрастающем порядке согласно коду ASCII. Комбина- ция \ с последующими 1, 2 или 3 восьмеричными цифрами обозначает литеру, ASCII-код которой задается этими цифрами. Если за \ следует какая-либо другая литера, эта комбинация обозначает эту последнюю литеру.
362 Приложение 1. Команды troff, nroff — системы форматирования текстов TROFF(l) troff [ опция ... ] [ файл ] ... nroff [ опция ... ] [ файл ] ... Система troff подготавливает для печати на фотонаборном устройстве текст, содержащийся в указанных файлах; система nroff делает то же самое для устройств типа пишущей машинки. Если ни одного параметра-файла не задано, читается файл стандартного ввода. Параметр, состоящий только из знака ми- нус, считается именем файла, соответствующего стандартному вводу. Опции Опции можно задавать в произвольном порядке, но перед име- нами файлов. —о список Распечатать только страницы, номера которых заданы в списке. Список состоит из чисел и диапазо- нов, разделенных запятыми. Диапазон п—т зада- ет страницы от п по т. Задание —и в начале списка означает страницы от начала до п; задание п— в конце списка означает страницы от п до конца до- кумента. —п р Присвоить первой сгенерированной странице номер Р- —s п Делать останов через каждые п страниц. Система nroff будет приостанавливать работу перед выводом каждых п страниц (по умолчанию п=1) и возобнов- лять ее при получении литеры новой строки. Это позволяет устанавливать на устройство вывода новые листы чистой бумаги. Система troff будет ос- танавливать фотонаборное устройство через каждые п страниц. Во время этой паузы можно сменить на- борные кассеты. Работа устройства возобновляется при нажатии на нем клавиши «старт». Перед вход- ными файлами обрабатывается файл макроопреде- лений /usr/lib/tmac/tmac.name. —г ап Присвоить регистру а (одна литера) значение п. — i После обработки входных файлов считать файл стандартного ввода. Только для nroff —Т имя Подготовить вывод для указанного терминала. Распознаются следующие имена: 37 — терминал модели 37 фирмы Teletype (подразумеваемое зна-
Приложение 1. Команды. 363 чение), trc300—GE TermiNet 300 (или любой другой терминал без средств перевода строк на полинтер- вала), 300S—DASI-300S, 300—DASI-300, 450—тер- минал DASI-450 (Diablo Hiterm). — е При выравнивании строк делать одинаковые интер- валы между словами, используя всю разрешающую способность устройства. — -h Использовать при выводе литеры табуляции вместо длинной последовательности пробелов. Это повы- шает скорость вывода и уменьшает размер выход- ного файла. Предполагается, что табуляции установлены через каждые 8 литер номинальной ширины. Только для troff — t Направить результаты в файл стандартного вывода вместо фотонаборного устройства. — f Воздержаться от прогона бумаги и останова фото- наборного устройства в конце работы. —w Дождаться освобождения фотонаборного устрой- ства, если оно в данный момент занято. —b Сообщить, занято или свободно фотонаборное уст- ройство. Обработка текста не выполняется. —а Послать представление документа в коде ASCII в файл стандартного вывода. —р п Печатать все литеры размером в п пунктов, сохра- няя в то же время все предписанные интервалы и сдвиги. Это уменьшает время, затрачиваемое на выполнение задания фотонаборным устройством. tsort — топологическая сортировка TSORT(l) tsort [ файл ] Команда tsort выдает в стандартный вывод полностью упоря- доченный список элементов в соответствии с отношением частич- ного порядка, заданным во входном файле. Если параметр файл не задан, используется стандартный файл ввода. Входной файл состоит из пар элементов (непустых цепочек литер), разделенных пробелами. Пары различных элементов за- дают порядок. Пары одинаковых элементов указывают на нали- чие этих элементов, но не определяют порядка.
364 Приложение 1. Команды. uniq — найти одинаковые строки в файле UNIQ(l) uniq [ —udc [ +n 1 [ —n ] ] [ вход [ выход ] 1 Команда uniq читает входной файл, сравнивая между собой соседние строки. В обычном режиме вторая и последующие копии строк исключаются; оставшиеся строки записываются в выходной файл. Повторяющиеся строки должны идти подряд, иначе они не будут обнаружены (см., однако, sort(l)). Если ис- пользуется флаг —и, выводятся строки, которые не повторяются в исходном файле. Опция —d указывает на то, что требуется вы- вести по одной копии строк-дубликатов. Обычный режим вывода представляет собой объединение режимов, задаваемых опциями —и и —d. Опция —с перебивает опции —и и —d и порождает выходной файл, который аналогичен файлу, выдаваемому в обычном режи- ме, но перед каждой его строкой помещается число, указываю- щее, сколько раз эта строка встречается в исходном файле. Параметры п задают отбрасывание начальной части каждой строки при выполнении сравнения: —п Первые п полей вместе с предшествующими им про- белами игнорируются. Поля определяются как це- почки отличных от пробелов литер, отделенные друг от друга пробелами. +п Первые п литер игнорируются. Пропуск литер осу- ществляется после пропуска полей. units — преобразование единиц измерения UNITS(l) units Программа units преобразует величины, выраженные в еди- ницах различных стандартных систем измерения, из одной сис- темы в другую. Преобразование выполняется в диалоге с пользо- вателем следующим образом (справа дается перевод): You have: inch Имеется: дюйм You want: ст Требуется: см * 2.54000е+00 / 3.93701е—01 Величина задается как мультипликативная комбинация единиц измерения, перед которой может стоять числовой множитель. Степень указывается суффиксом в виде целого положительного числа, деление —• обычным знаком;
Приложение 1. Команды. 365 You have: 15 pounds force/in2 Имеется: 15 фунтов/дюйм You want: atm Требуется: атм * 1.02069+00 / 9.79730—01 Команда units выполняет только преобразования, сводящиеся к операциям умножения и деления. Так, она может преобразо- вывать температуру по шкале Кельвина в температуру по шкале Ранкина, но не может преобразовать температуру по Цельсию в температуру по Фаренгейту. Распознаются большинство обще- принятых единиц измерения, их сокращения и метрические при- ставки, а также изрядное количество экзотических единиц и не- сколько мировых констант, включая: pi Отношение длины окружности к ее диаметру. с Скорость света. е Заряд электрона. g Ускорение силы тяжести. force То же, что и g. mole Число Авогадро. water Давление столбца воды единичной высоты. аи Астрономическая единица. Фунт (pound) — единица массы. Составные названия единиц записываются слитно, например lightyear (световой год). Англий- ские единицы, отличающиеся от их американских разновидно- стей, имеют префикс br: brgallon (английский галлон). Денежные единицы записываются как belgiumfranc (бельгийский франк), britainpound (английский фунт) и т. п. Полный список единиц можно получить, выполнив команду cat /usr/lib/units. uucp — копирование UNIX—UNIX UUCP(l) uucp [ опция 1 ... исходный-файл ... целевой-файл Команда uucp копирует заданные исходные-файлы в заданный целевой-файл. Имя файла может быть либо составным именем на вашей машине, либо может иметь вид имя-системы! составное-имя где имя-системы берется из списка имен систем, известного команде uucp. Содержащиеся в составном имени метасимволы ?*[ ] языка-оболочки будут проинтерпретированы в соответству- ющей системе. Составные имена файлов в команде uucp могут быть следую- щими:
366 Приложение 1. Команды. • Полное составное имя. • Составное имя, начинающееся с ^пользователь, где пользователь — регистрационное имя некоторого поль- зователя в соответствующей системе; эта приставка за- меняется именем регистрационного оглавления данного пользователя. • Все остальное считается именем относительно текущего оглавления. Если составное имя файла в удаленной системе задано не- правильно, копирование не будет выполнено. Если в роли целе- вого файла указано оглавление, используется последняя ком- понента имени исходного файла. Если целевое оглавление ^пользователь недоступно для uucp, данные копируются в оглав- ление /usr/spool и пользователь уведомляется об этом через по- чтовую службу mail(l). Система uucp сохраняет при пересылке полномочия на вы- полнение файла и устанавливает полномочия 0666 на чтение и запись (см. chmod(2)). Опции — d Создать все оглавления, необходимые для копиро- вания файлов. — с Использовать при копировании сам исходный файл, не копируя его в оглавлении /usr/spool. — m Послать почтовое сообщение заказчику после за- вершения пересылки. vi — экранный (визуальный) редактор VI(1) vi [ —г ] [ +запрос ] [ —1 ] [ —wn ] имя ... Экранный редактор текстов vi был описан в гл. 3. Опции — г х Восстановить файл х после сбоя или разрыва связи с терминалом. — г Выдать список сохраненных файлов. — w п Установить начальный размер окна равным п. — х Запросить ключ, который будет использоваться для шифровки и дешифровки содержимого файла (см. также crypt(l)). -^запрос Прежде чем считывать запросы редактирования с терминала, выполнить заданный запрос. Это по-
Приложение 1. Команды. 367 лезно для начальной установки текущей позиции в файле. По умолчанию, редактирование начина- ется с последней строки текста. wc—счетчик слов WC(1) wc [ —Iwc ] [ файл ] ... Команда wc подсчитывает число строк, слов и литер в файлах с заданными именами или в стандартном файле ввода, если не задано ни одного имени. Словами считаются цепочки литер, разделенные литерами типа пробел, табуляция, новая строка. Если задана опция, начинающаяся с одной из букв Iwc, то буквы 1, w, с в ней задают подсчет строк, слов и литер соответ- ственно. По умолчанию берется —Iwc. who — кто работает в системе WHO(l) who [ who-файл ] [ am i ] Команда who без параметров выдает регистрационное имя, имя терминала и время входа в систему для каждого пользова- теля, работающего в данный момент в системе. Эта информация берется из системного файла /etc/utmp. Если в команде указано имя файла, то вместо /etc/utmp будет просматриваться данный файл. Обычно таким файлом бывает /usr/adm/wtmp, который со- держит записи о всех сеансах работы в системе с момента своего создания. В этом случае команда who сообщает информацию о всех входах в систему, выходах из системы и крахах системы со времени создания файла wtmp. Для каждого входа в систему распечатываются имя пользователя, имя терминала (префикс /dev/ опускается), дата и время входа. Если задан параметр, аналогичная строка, но без имени. пользователя выдается для каждого выхода из системы. При наличии двух параметров, как при обращении who am I, а также who are you («кто я» и «кто вы»), команда who сообщает, под чьим именем вы работаете в системе. write — послать сообщение на терминал другого пользователя WRITE(l) write пользователь [ имя-tty ] Команда write копирует строки с вашего терминала на терми- нал другого пользователя. При вызове она посылает сообщение Message from ваше-имя имя-вашего-терминала ...
368 Приложение 7. Команды. («сообщение от...»). Получателю в этот момент следует вызвать write для передачи сообщений в обратном направлении.. Пере- дача сообщений продолжается до тех пор, пока не будет введен признак конца файла или получено прерывание. Когда это про- исходит, write посылает на другой терминал сообщение EOT и завершает работу. Если вы хотите послать сообщение пользователю, вошедшему в систему одновременно с нескольких терминалов, то можете воспользоваться параметром имя-tty для указания имени нуж- ного терминала. Можно запретить или разрешить передачу сообщений на тер- минал, воспользовавшись командой mesg(l). Первоначально передача сообщений на терминал разрешена. Некоторые коман- ды, в частности nroff и рг(1), запрещают вывод на терминал по- сторонних сообщений для того, чтобы они не испортили выводи- мый текст. Если введенная строка начинается со знака !, то остаток строки интерпретируется как команда и передается для выполне- ния программе-оболочке. уасс — «еще один компилятор компиляторов» YACC(l) уасс [ —vd ] грамматика Система уасс преобразует контекстно-свободную грамматику в набор таблиц для простого LR(1 ^распознавателя. Грамматика может быть неоднозначной. Для разрешения неоднозначностей используется задание правил предшествования. Выходной файл y.tab.c компилируется компилятором С в про- грамму yyparse. Эта программа загружается вместе с программой лексического анализа yylex, а также с головной подпрограммой main и подпрограммой обработки ошибок ууеггог. Все эти под- программы поставляются пользователем. Для порождения лек- сических анализаторов для уасс полезен 1ех(1). Если задан флаг — v, то подготавливается файл y.output, содержащий описание таблиц разбора с указанием конфликтных ситуаций, порожденных неоднозначностями заданной грамма- тики. ' Если используется флаг —d, то порождается файл y.tab.h, содержащий определения (^define), связывающие заданные пользователем «имена лексем» с назначенными системой уасс «кодами лексем». Это позволяет использовать коды лексем, в дру- гих исходных файлах, отличных от y.tab.c.
ПРИЛОЖЕНИЕ 2 СИСТЕМНЫЕ ФУНКЦИИ access — определить доступность файла ACCESS(2) access(name, mode) char *name; Системная функция access проверяет доступность файла с име- нем пате для использования в режиме mode. Режим может иметь значения 4 (чтение), 2 (запись), 1 (исполнение) или их комби- нацию. Если задан режим 0, то проверяется, что все оглавления, расположенные на пути к файлу, доступны для поиска, а сам файл существует. Если файла с именем name найти не удалось или же отсутст- вуют требуемые права доступа, возвращается соответствующая индикация ошибки. При отсутствии прав доступа возвращается —1, а код ошибки помещается в еггпо(2).. Если проверка дала положительный результат, возвращается 0. Идентификаторами пользователя и группы, по отношению к которым проверяются права доступа, являются действительные идентификаторы пользователя и группы процесса. Поэтому дан- ную системную функцию можно использовать и для программ с установкой идентификации при выполнении. Проверяются только биты, определяющие права доступа. Функция access может сообщить, что оглавление доступно на запись, но попытка открыть его на запись обречена на неудачу (хотя в нем можно создавать файлы). Файл может быть объявлен выполнимым, однако ехес потерпит неудачу, если этот файл имеет неправильный формат. alarm— возбудить сигнал через заданное время ALARA1(2) alarm(seconds) unsigned seconds;
370 Приложение 2. Системные функции Системная функция alarm вызывает возбуждение сигнала SIGALRM(14) в вызвавшем ее процессе через интервал времени (в секундах), заданный параметром. Процесс завершится, если этот сигнал не будет перехвачен или проигнорирован. Запросы на возбуждение сигнала не накапливаются. После- дующие запросы переустанавливают будильник. Если парамет- ром является 0, запрос на возбуждение сигнала аннулируется. Поскольку будильник имеет разрешающую способность 1 се- кунда, сигнал может быть возбужден раньше на время до 1 се- кунды; из-за задержек диспетчеризации возобновление выпол- нения при перехвате сигнала может задержаться на произволь- ное время. Максимальный интервал времени, который может быть задан при обращении к функции alarm, ограничен размером целого без знака. Возвращаемым значением является интервал времени, остав- шийся до возбуждения сигнала от предыдущей установки бу- дильника. brk, sbrk — изменить размер памяти процесса BRK(2) char *brk(addr) char *sbrk(incr) Системная функция brk устанавливает границу памяти рав- ной addr. Граница памяти — это величина, которая интерпрети- руется системой как наименьший адрес памяти, не используемой программой. Граница памяти округляется вверх до ближайшего кратного 64 байтам на PDP 11, 256 байтам на Inter data 8/32 и 1024 байтам на VAX 11. Ячейки с адресом addr и выше, но ниже указателя стека не входят в адресное пространство процесса, и поэтому при обращении к ним происходит нарушение защиты памяти. Альтернативная функция sbrk добавляет к адресному прост- ранству программы еще incr байт и возвращает указатель на на- чало этой новой области. Когда (в результате ехес) программа начинает выполняться, граница памяти устанавливается по наибольшему адресу, опре- деленному в этой программе и ее областях данных. Поэтому по- требность в использовании данных системных функций возни- кает обычно только в программах с расширяющимися областями данных. chdir— изменить текущее (рабочее) оглавление CHDIR(2) chdir(dirname) char *dirname;
Приложение 2. Системные функции 371 Параметр dirname представляет собой адрес цепочки, содер- жащей составное имя оглавления и оканчивающейся нулевым байтом. Функция chdir делает это оглавление текущим (рабочим) оглавлением. Имена файлов, не начинающиеся с /, считаются заданными относительно текущего (рабочего) оглавления. chmod — изменить полномочия файла CHMOD(2) chmod(name, mode) char *name; Изменить режим использования файла так, чтобы он соответ- ствовал параметру mode. Имя файла задается в виде цепочки литер (с пустой литерой в конце), на которую указывает пара- метр name. Режимы определяются как комбинации следующих значений: 04000 Установить идентификатор пользователя при выпол- нении. 02000 Установить идентификатор группы при выполнении. 01000 Сохранить текстовой образ программы после выполне- ния. 00400 Право на чтение для владельца. 00200 Право на запись для владельца. 00100 Право на выполнение (на поиск в оглавлении) для владельца. 00070 Права на чтение, запись, выполнение (поиск) для чле- нов группы. 00007 Права на чтение, запись, выполнение (поиск) для прочих пользователей. Если программный текст выполняемого файла является разделя- емым, то флаг 01000 предотвращает уничтожение текстового об- раза этой программы в области своппинга при завершении ра- боты последнего пользователя. Только владелец файла (или суперпользователь) может из- менить режим 01000. Только суперпользователь может устано- вить режим 01000. В некоторых системах запись или изменение владельца файла вызывают сброс флага установки идентификации пользователя при выполнении. Это делает систему несколько более надежной, так как обеспечивает защиту файлов с установкой идентификации пользователя при выполнении от остальных файлов с установкой идентификации при их модификации.
372 Приложение 2. Системные функции close — закрыть файл CLOSE(2) close(fildes) Команда close закрывает файл, связанный с заданным дескрип- тором файла fildes. Все файлы закрываются автоматически при выполнении системой функции exit. Однако, так как имеется ог- раничение на число одновременно открытых файлов для одного процесса, функция close необходима в программах, имеющих дело с большим количеством файлов. Файлы закрываются при завершении процесса. Некоторые файлы с большими номерами дескрипторов закрываются автома- тически при выполнении системной функции ехес(2). creat — создать новый файл CREAT(2) creat(name, mode) char *name; Системная функция creat создает новый файл и подготавли- вает для перезаписи существующий файл с именем, задаваемым параметром name — адресом цепочки литер, завершающейся пустой литерой. Если файл ранее не существовал, то при созда- нии он получает полномочия mode, модифицированные согласно маске процесса (см. umask(2)). Способ задания полномочий описан в chmod (2). Если же файл уже существует, его владелец и полномочия остаются прежними, однако он обрезается до нулевой длины. Кроме того, файл открывается на запись. Возвращаемым зна- чением является дескриптор этого файла. Полномочия mode задаются произвольным образом; не тре- буется, чтобы они включали право на запись. Однако супер- пользователь может читать любой файл независимо от его полно- мочий. dup, dup2 — сдублировать дескриптор открытого файла DUP(2) dup(fildes) int fildes; dup2(fildes, fildes2) int fildes, fildes2; По заданному дескриптору файла fildes системная функция dup выделяет другой дескриптор файла, эквивалентный исход- ному. Возвращается новый дескриптор файла.
Приложение 2. Системные функции 373 Во втором варианте этой функции fildes — дескриптор фай- ла, соответствующий открытому файлу, fildes2 — неотрицатель- ное целое число, меньшее, чем максимально возможное число дескрипторов файлов (приблизительно 19). В результате выпол- нения системной функции dup2 дескриптор fildes2 будет указы- вать на тот же файл, что и дескриптор fildes. Если с дескриптором fildes2 уже был связан открытый файл, он предварительно за- крывается. еггпо — коды ответа системных’функций ERRNO(2) ^include <errno.h> На ошибочную ситуацию указывает возвращаемое системной функцией значение, невозможное в случае нормального заверше- ния. Почти всегда это —1; более точная информация содержится в описаниях отдельных команд. Кроме того, через внешнюю переменную еггпо доступен код ошибки. Значение еггпо не обну- ляется при успешном завершении системных функций, поэтому его следует проверять только при возникновении ошибки. Имеются таблица сообщений, связанных с каждой ошибкой, и подпрограмма, печатающая эти сообщения (см. реггог(З)). Ниже приводятся коды ошибок, их названия и сообщения, выдаваемые подпрограммой реггог. 1 EPERM Not owner (Не владелец) В типичном случае эта ошибка указывает на то, что кто-то кроме владельца файла или суперпользова- теля пытается изменить этот файл недозволенным образом. Этот код возвращается также при попытке обычного пользователя выполнить действия, дозво- ленные только суперпользователю. 2 ENOENT No such file or directory (Нет такого файла или оглавления) Эта ошибка возникает, когда задано имя файла и этот файл должен существовать, но на самом деле он не существует либо когда не существует одно из оглав- лений, входящих в составное имя файла. 3 ESRCH No such process (Нет такого процесса) Процесс, номер которого был задан в качестве пара- метра системной функции signal или ptrace, не су- ществует или уже завершился. 4 EINTR Interrupted system call (Прерывание при выполнении системной функции) Во время выполнения системной функции был полу- чен асинхронный сигнал (например, сигнал преры-
374 Приложение 2. Системные функции вания или выхода), для которого пользователь задал перехват. После обработки этого сигнала осуществ- ляется возврат из прерванной системной функции с индикацией данной ошибочной ситуации. 5 ЕЮ I/O error (Ошибка ввода-вывода) Во время выполнения операции read или write прои- зошла какая-либо физическая ошибка ввода-вывода. В некоторых случаях этот код ошибки может быть получен не сразу, а при следующем обращении к системной функции. 6 ENXIO No such device or address (Нет такого устройства или адреса) Операция ввода-вывода через специальный файл ссылается на несуществующее устройство либо про- изошел выход за пределы физической памяти уст- ройства. Эта ситуация возникает также в случаях, если, например, не подключено лентопротяжное уст- ройство или не установлен пакет магнитных дисков. 7 E2BIG Arg list too long (Слишком длинный список парамет- ров) Длина списка параметров, заданного в системной функции ехес, превышает 5120 или 10240 байт. Это число зависит от системы. 8 ENOEXEC Ехес format error (Ошибка в формате выполнимого файла) Делается запрос на выполнение файла, который, хотя и имеет соответствующие полномочия, не является файлом типа a.out 9 EBADF Bad file number (Неправильный номер файла) Либо дескриптор файла не связан с открытым фай- лом, либо сделан запрос на чтение (запись) файла, открытого только на запись (чтение). 10 ECHILD No children (Отсутствуют порожденные процессы) Обращение к системной функции ожидания заверше- ния порожденных процессов wait, в то время как у процесса не осталось порожденных процессов. 11 EAGA IN No more processes (Слишком много процессов) При выполнении fork происходит переполнение сис- темной таблицы процессов либо пользователю не раз- решается создавать процессы сверх числа уже соз- данных. 12 ENOMEM Not enough core (Не достаточно оперативной памяти) При выполнении системной функции ехес или brk программа запрашивает больше (оперативной) па- мяти, чем система может ей предоставить. Эта ситуа-
Приложение 2, Системные функции 375 ция не временная: максимальный размер памяти яв- ляется параметром системы. Данная ошибочная си- туация может также возникнуть, если программный сегмент, сегмент данных и стековый сегмент построе- ны так, что требуют слишком много регистров сег- ментации. 13 EACCES Permission denied (Нарушение полномочий) Попытка доступа к файлу способом, запрещенным системой защиты. 14 ЕFAULT Bad address (Неправильный адрес) При обращении к параметрам системной функции произошло аппаратное прерывание. 15 ENOTBLK Block device required (Требуется блочное уст- ройство) Вместо требуемого блочного устройства указан обыч- ный файл (например, в системной функции mount). 16 ЕВ U SY Mount device busy (Монтируемое устройство за- нято) Попытка смонтировать устройство, которое уже смонтировано, либо размонтировать устройство, со- держащее активное оглавление (открытый файл, текущее оглавление, смонтированный файл, актив- ный программный сегмент). 17 EEXIST File exists (Файл существует) Задан существующий файл в неподходящем контек- сте (например, в системной функции link). 18 EXDEV Cross-device link (Ссылка на другое устройство) Попытка создать ссылку на файл, находящийся на другом устройстве. 19 ENODEV No such device (Нет такого устройства) Попытка применить к устройству неподходящую операцию. Например, чтение из устройства, которое может выполнить только запись. 20 ENOTDIR Not a directory (Не оглавление) В контексте, где требуется оглавление, задано не оглавление (например, в составном имени или в роли параметра chdir). 21 EISDIR Is a directory (Это оглавление) Попытка записи в оглавление. 22 EINVAL Invalid argument (Ошибка в параметре) Какая-либо ошибка при задании параметра: попытка размонтировать несмонтированное устройство, зада- ние несуществующего сигнала в системной функции signal, чтение или запись файла после того, как функ- ция Iseek возвратила для него отрицательный ука- затель.
376 Приложение 2. Системные функции 23 24 25 26 27 28 29 30 31 32 Устанавливается также и математическими функ- циями. ENFILE File table overflow (Переполнение таблицы фай- лов) Переполнение системной таблицы открытых файлов. Временно невозможно открывать новые файлы. ЕМ FILE Too many open files (Слишком много открытых файлов) В обычной конфигурации можно открыть 20 файлов в одном процессе. ENOTTY Not a terminal (Не терминал) Файл, указанный при обращении к stty или gtty, не является терминалом или другим устройством, к которому применимы эти системные функции. ETXTBSY Техт file busy (Программный файл занят) Попытка выполнить разделяемую программу, кото- рая в данный момент открыта на запись (или на чте- ние!). Также попытка открыть на запись разделяе- мую программу, которая в данный момент выпол- няется. EFBIG File too large (Файл слишком большой) Размер файла превышает максимальную величину, допустимую в системе (около 10е байт). ENOSPC No space left on device (Исчерпано пространство на устройстве) Во время выполнения операции записи write в обыч- ный файл не оказалось свободного пространства на устройстве. ESPIPE Illegal seek (Неправильная установка позиции) Обращение к системной функции Iseek с параметром- транспортером. Эта ошибка возникает также при задании других устройств, для которых невозможно выполнить установку позиции. EROFS Read-only file system (Файловая система смонти- рована только на чтение) Попытка изменить файл или оглавление на устрой- стве, которое смонтировано только на чтение. EMLINK Too many links (Слишком много ссылок) Попытка создать более 32 767 ссылок на файл. EPIPE Broken pipe (Разорванный транспортер) Запись в транспортер, однако процесса, который смог бы прочитать данные из этого транспортера, не существует. В этой ситуации обычно возбуждается сигнал; код ошибки возвращается, если этот сигнал игнорируется.
Приложение 2. Системные функции 377 33 EDOM Math argument (Ошибка в задании параметра мате-. матической функции) Значение параметра функции из библиотеки матема- тических функций (ЗМ) лежит вне области опреде- ления этой функции. 34 ERANGE Result too large (Результат слишком велик) Значение функции из библиотеки математических функций (ЗМ) не представимо в машинном формате. execl, execv — выполнить файл ЕХЕС(2) execl(name, argO, argl, argn, 0) char #name, *argO, *argl, *argn; execv(name, argv) char *name, *argv[ ]; extern char **environ; Системная функция exec во всех ее разновидностях заменяет в оперативной памяти процесса вызывающую программу про- граммой из указанного файла, а затем передает управление на ее точку входа. В случае успешного завершения возврата из функции ехес не бывает, образ памяти вызывающей программы теряется. При выполнении ехес открытые файлы остаются открытыми, если только не были приняты специальные меры. Игнорируемые сигналы и сигналы со стандартным состоянием сохраняют свое состояние, но перехватываемые сигналы (см. signal(2)) переуста- навливаются в стандартное состояние. Каждый пользовательский процесс имеет действительные идентификаторы пользователя и группы и эффективные иденти- фикаторы пользователя и группы. Действительный идентифика- тор идентифицирует пользователя системы, а эффективный иден- тификатор определяет права доступа процесса. Если заданный файл имеет полномочия на установку идентификации пользовате- ля и группы при выполнении, то ехес изменяет эффективные идентификаторы пользователя и группы на идентификаторы поль- зователя и группы владельца этого файла. Действительный иден- тификатор пользователя не изменяется. Параметр name представляет собой указатель на цепочку литер, содержащую имя файла, который требуется выполнить. Указатели arglO], argil], ... содержат адреса цепочек литер — параметров вызова. Цепочки оканчиваются пустой литерой. По соглашению, arglO] является именем вызываемого файла. Для С-программ имеется два интерфейса. Функция execl ис- пользуется, когда требуется выполнить известный файл с извест- ными параметрами. Параметрами execl являются цепочки литер,
378 Приложение 2 Системные функции содержащие имя вызываемого файла и значения параметров вы- зова этого файла. По соглашению, первый параметр совпадает с именем файла (или содержит его последнюю компоненту). Список параметров должен заканчиваться нулевым указателем. Вариант execv используется, когда количество параметров вызова заранее не известно. Параметрами execv являются имя файла, который требуется выполнить, и вектор цепочек, содер- жащих параметры выполнения. За указателем на последнюю цепочку в векторе должен следовать нулевой указатель. По соглашению, при вызове функции main количество пара- метров argc всегда не менее единицы, а первый элемент вектора параметров argv указывает на цепочку литер, содержащую имя файла. Вектор argv, переданный в функцию main, можно непосредст- венно использовать в обращении к системной функции execv, поскольку argv[argc] равно 0. Параметр envp функции main представляет собой указатель на вектор цепочек литер, составляющих среду процесса. Каждая цепочка состоит из имени, знака = , цепочки-значения и оканчи- вается пустой литерой. Вектор указателей заканчивается пустым указателем. Начальная подпрограмма раскрутки (при программировании на С) помещает копию envp в глобальную ячейку environ, кото- рая используется в execv и ехес! для передачи среды в програм- мы, вызываемые из данной программы. Для явной передачи среды подпрограммы семейства ехес используют следующие функции нижнего уровня: execve(name, argv, environ); execle(name, argO, argl, argn, 0, environ); Функции execlp и execvp вызываются с теми же параметрами, что и функции ехес! и execv, но, как и оболочка, ищут выполнимый файл в списке оглавлений. Список оглавлений берется из среды. Чтобы обеспечить выполнение командных файлов, составлен- ных для различных программ, принято следующее соглашение. Если первыми двумя литерами выполняемого файла являются #!, то ехес пытается считать из этого файла имя программы, ко- торую требуется использовать как командный интерпретатор для данного командного файла. Интерпретатору можно передать один параметр, задаваемый после имени интерпретатора. Его длина вместе с длиной имени интерпретатора не должна превышать 32 литер. Пробел или табуляция после =Ц=! обязательны, а имя интерпретатора должно быть задано явно (поиск по оглавлениям не выполняется).
Приложение 2. Системные функции 379 exit — завершить процесс ЕХ1Т(2) exit(status) int status; .exit(status) int status; Системная функция exit представляет собой обычное средство завершения процесса. Функция exit закрывает все файлы дан- ного процесса и уведомляет родительский процесс, когда он вы- полняет функцию ожидания wait. Родительскому процессу пере- даются младшие 8 бит статуса завершения status. Возврата из этой функции не бывает. С-функция exit может вызвать выполнение завершающих действий, прежде чем процесс будет окончательно завершен. Функция _exit не выполняет никаких завершающих действий; ее следует использовать для завершения порожденных процес- сов, созданных системной функцией fork(2), для того чтобы избе- жать повторного выталкивания содержимого выходных буферов. fork — образование нового процесса FORK(2) fork( ) Системная функция fork — это единственное средство для создания нового процесса. Образ памяти нового процесса яв- ляется копией образа памяти процесса, обратившегося к fork. Единственное различие заключается в том, что значение, возвра- щаемое в старый (родительский) процесс, содержит идентифика- тор нового (порожденного) процесса, в то время как значение, возвращаемое в порожденный процесс, равно 0. Идентификатор процесса лежит в диапазоне от 1 до 30 000. Тот же идентифи- катор возвращается функцией wait(2). Файлы, открытые до обращения к fork, становятся общими для обоих процессов и имеют общий указатель чтения-записи. В частности, именно таким способом передаются файлы стандарт- ного ввода и вывода; таким же образом устанавливается связь через транспортеры. getuid, getgid, geteuid, getegid — получить идентификатор пользователя и группы GETUID(2) getpid — получить идентификатор процесса getuid( ) geteuid( ) getgid( ) getegid( ) getpid( )
380 Приложение 2. Системные функции Функция getuid возвращает действительный идентификатор пользователя обратившегося к ней процесса, а функция geteuid — эффективный идентификатор пользователя. Действительный идентификатор пользователя идентифицирует пользователя, от имени которого запущен процесс. В противоположность ему эффективный идентификатор пользователя определяет, чьими правами доступа обладает процесс в данный момент. Действи- тельный идентификатор пользователя используется в програм- мах с флагом установки идентификации пользователя при выполнении для того, чтобы узнать, кто к ним обратился. Функция getgid возвращает действительный идентификатор группы, а функция getegid — эффективный идентификатор группы. Функция getpid возвращает идентификатор обратившегося к ней процесса. Чаще всего она используется для порождения уникальных имен для временных файлов. ioctl, stty, gtty — управление устройством IOCTL(2) # include <sgtty.h> ioctl(fildes, request, argp) struct sgttyb *argp; stty(fildes, argp) struct sgttyb *argp; gtty(fildes, argp) struct sgttyb *argp; Системная функция ioctl выполняет ряд различных операций для литерных специальных файлов (устройств), заданных де- скриптором файла fildes. Функции stty и gtty позволяют устанав- ливать и считывать некоторые параметры устройства типа тер- миналов и эквивалентны ioctl(fildes, TIOCSETP, argp) ioctl(fildes, TIOCGETP, argp) соответственно. Некоторые способы обращения к ioctl (2) предназначены для терминалов. В большинстве из них используется следующая структура, определенная в <sgtty.h>: struct sgttyb { char sg_ispeed; char sg.ospeed; char sg.erase; char sg_kill; j int sg.flags; };
Приложение 2. Системные функции 381 Поля sg_ispeed и sg_ospeed описывают скорость ввода и вывода устройства согласно следующей таблице, соответствующей ин- терфейсу DH-11 фирмы DEC. Если используется другое оборудо- вание, то попытки установить невозможную для него скорость игнорируются. Символические значения, приведенные в таблице, описаны в файле заголовков <sgtty.h>. ВО 0 (разорвать линию связи) В50 1 50 бод В75 2 75 бод ВП0 3 ПО бод В134 4 134.5 бод В150 „5 150 бод В200 6 200 бод В300 7 300 бод В600 8 600 бод В1200 9 1200 бод В1800 10 1800 бод В2400 11 2400 бод В4800 12 4800 бод В9600 13 9600 бод ЕХТА 14 Внешний А ЕХТВ 15 Внешний В В текущей конфигурации системы для телефонных линий в действительности поддерживаются только скорости ПО, 150, 300 и 1200 бод. Преобразование кодов литер и запросы управ- ления линией связи для устройств серии IBM 2741 (134.5 бод) должны быть реализованы в программе пользователя. Полудуп- лексный режим, требуемый для модема 202 (1200 бод), не предус- мотрен; модемы 212 в режиме полного дуплекса работают хорошо. Поля sg_erase и sg_kill структуры-параметра задают литеры стирания и отмены соответственно. (Подразумеваемыми литерами стирания и отмены являются =£ и @.) Поле sg_flags структуры-параметра содержит ряд битов, которые определяют внутрисистемные характеристики терминала: ALLDELAY 0177400 Маска алгоритма задержек BSDELAY 0100000 Вид задержки для литеры возврата на шаг (не реализовано): BS0 0 BS1 0100000 VTDELAY 0040000 Вид задержки для перевода формата и вертикальной табуляции: FF0 0 FF1 0040000 CRDELAY 0030000 Вид задержки для литеры возврата каретки:
382 Приложение 2. Системные функции CR0 CR1 CR2 CR3 TBDELAY TAB0 ТАВ1 ТАВ2 XTABS NLDELAY NL0 NL1 NL2 NL3 EVENP 0 0010000 0020000 0030000 0006000 Вид задержки для литеры табуляции: 0 0001000 0004000 0006000 0001400 Вид задержки для литеры новой строки: 0 0000400 0001000 0001400 0000200 Выполнять контроль по четности при вводе (большинство терминалов) ODDP 0000100 Выполнять контроль по нечетности при вводе RAW 0000040 «Сырой» режим: прием по одной литере, 8-разрядный интерфейс CRMOD 0000020 Преобразовывать ВК в ПС; в качестве эхо для ПС или ВК использовать ком- бинацию ВК-ПС ECHO 0000010 Отображение вводимых данных (пол- ный дуплекс) LCASE 0000004 При выводе преобразовывать пропис- ные буквы в строчные CBREAK 0000002 Прием по одной литере (без буфериза- ции строки) TANDEM 0000001 Автоматическое управление потоком Биты задержек определяют интервалы времени, на которые при- останавливается передача при выводе на терминал некоторых литер. Эти интервалы позволяют устройствам завершить механи- ческие и другие перемещения. Во всех случаях значения 0 озна- чает отсутствие задержки. Задержки для литер возврат на шаг в настоящее время игно- рируются, но могут использоваться для терминалов Terminet 300. Задержка для перевода формата и вертикальной табуляции, если она задана, длится около 2 секунд. Задержка на возврат каретки первого типа длится около 0.08 секунды и подходит для терминалов Terminet 300. Задержка второго типа продолжается 0.16 секунды и пригодна для терми- налов VT05 и TI 700. Задержка третьего типа не реализована и равна нулю.
Приложение 2. Системные функции 383 Задержка для литеры новой строки типа 1 зависит от теку- щей позиции и рассчитана на терминалы модели 37 фирмы Tele- type. Задержка типа 2 используется для VT05 и равна пример- но 0.10 секунды. Задержка типа 3 не реализована и равна нулю. Задержка на табуляцию типа 1 зависит от величины требуе- мого перемещения и рассчитана на модель 37 фирмы Teletype. Третий тип задержки — XTABS — вовсе не является задерж- кой; он вызывает замену табуляций при выводе соответствую- щим количеством пробелов. Литеры с ошибочным паритетом (который определяется битами 0200 и 0100) игнорируются. В «сыром» режиме каждая литера передается в программу непосредственно, не дожидаясь окончания набора целой строки. Литеры стирания и отмены не обрабатываются; не интерпрети- руются специальным образом признак конца файла (EOT), ли- тера прерывания (DEL) и литера выхода (FS). Не выполняется никаких задержек, вводимый текст не отображается обратно на терминале и не выполняется преобразование литер. Литерой счи- таются все 8 бит как при вводе, так и при выводе (проверка па- ритета оставляется программе пользователя). Режим 020 вызывает преобразование вводимых литер воз- врата каретки в литеры новой строки. Ввод как литеры возврат каретки (ВК), так и литеры перевод строки (ПС) вызывает об- ратное отображение комбинации ПС-ВК (для терминалов с функ- цией новой строки). Режим CBREAK представляет собой разновидность полу- дуплексного режима. Программы могут читать литеры по мере их ввода, не дожидаясь завершения набора целой строки. Однако литеры прерывания и выхода обрабатываются, обычным образом выполняются задержки, преобразование прописных букв в строч- ные, действуют режимы CRMOD, XTABS и ECHO и проверка паритета при вводе. С другой стороны, литеры стирания, отмены, а также \ и EOT теряют свой специальный смысл. В режиме TANDEM система посылает литеру приостановки (по умолчанию DC3) при возникновении угрозы переполнения входного буфера и литеру возобновления (по умолчанию DC1), когда во входном буфере освобождается достаточно места. Этот режим полезен для управления потоком в случае, если роль тер- минала выполняет другая ЭВМ, соблюдающая данные согла- шения. Один из способов обращения к ioctl имеет вид 4k include <sgtty.h> ioctl(fildes, request, arg) struct sgttyb *arg; В качестве параметра request можно задавать следующие запросы;
384 Приложение 2. Системные функции TIOCGETP Считать параметры терминала и записать их в струк- туру, на которую указывает указатель. TIOCSETP Установить параметры терминала согласно струк- туре, на которую указывает указатель. Прежде чем изменять параметры, система дожидается заверше- ния вывода и отбрасывает все введенные, но не про- читанные литеры. TIOCSETN Переключение с режимов RAW и CBREAK может вызвать получение нескольких посторонних входных литер. В следующих запросах параметр arg игнорируется: TIOCEXCL Установить режим монопольного пользования: за- прещается открывать файл до тех пор, пока он не будет закрыт. TIOCNXCL Отменить монопольный режим TIOCHPCL Разорвать связь с терминалом, когда файл будет за- крыт последний раз. Этот код полезен, когда для связи используется устройство автоматического вы- зова. TIOCFLUSH Вытолкнуть содержимое входных и выходных бу- феров. Следующие запросы изменяют специальные литеры терми- нала. Параметр arg при этом является указателем на описанную в <sgtty.h> структуру следующего вида: struct tchars { char t_intrc; char t_quitc; char t_startc; char t_stopc; char t_eofc; char t_brkc; /* прерывание #/ /* выход */ /* возобновление вывода */ /* приостановка вывода */ /* конец файла */ /* разделитель входных строк (типа НС) */ Подразумеваемые значения этих литер зависят от системы. Ли- терное значение —1 отменяет специальное значение соответствую- щей литеры. Литера t_brkc (по умолчанию —1) действует, как литера новой строки: она также завершает «строку», отображает-
Приложение 2, Системные функции 385 ся обратно на терминал и передается в программу. Литеры при- остановки и возобновления вывода могут быть одинаковыми. Делать одинаковыми другие специальные литеры (включая ли- теры стирания и отмены), по-видимому, не имеет смысла, так как это приводит к противоречивым результатам. Эти запросы имеют вид: TIOCSETC Заменить специальные литеры литерами, заданными в структуре. TIOCSETP Сделать специальными литерами литеры, заданные в структуре. kill — послать сигнал процессу K1LL(2) kill(pid, sig) Системная функция kill посылает сигнал sig процессу, за- данному идентификатором процесса pid. Посылающий и полу- чающий процессы должны иметь одинаковый эффективный иден- тификатор пользователя, иначе вызывающей стороной должен быть супер пользователь. Если задан нулевой идентификатор процесса, сигнал посы- лается всем другим процессам, входящим в группу процессов отправителя сигнала. Процесс может послать сигнал себе. link — создать ссылку на файл LINK(2) link(namel, name2) char *namel, *name2; Создается ссылка на файл с именем namel; ссылке присваи- вается имя name2. Оба параметра могут быть произвольными составными именами при единственном ограничении: оба файла должны содержаться в одной и той же файловой системе. Iseek — передвинуть указатель чтения-записи LSEEK(2) long lseek(fildes, offset, whence) long offset; Дескриптор файла Hides ссылается на файл, открытый на чтение или на запись. Указатель чтения (соответственно, записи) для этого файла переустанавливается в зависимости от значения параметра whence (О, I или 2), как показано ниже. 13 С. Баурн
386 Приложение 2. Системные функции Возвращается новое значение указателя чтения-записи. При установке указателя за конец файла с последующей записью образуется промежуток, который не занимает физического про- странства в файловой системе. При чтении из этого промежутка считываются нули. О Значением указателя становится offset байт. 1 К текущему значению указателя прибавляется offset. 2 Значением указателя становится размер файла плюс offset. nice — установить приоритет процесса NICE(2) nice(incr) Диспетчерский приоритет процесса увеличивается на incr. Положительные значения параметра задают более низкий при- оритет по сравнению с обычным. Для программ пользователя, выполнение которых требует значительного времени, рекомен- дуется приоритет 10. Отрицательные приращения приоритета игнорируются, за исключением случая, когда их задает суперпользователь. При- оритет ограничен диапазоном от —20 (наиболее приоритетный) до 20 (наименее приоритетный). При выполнении fork (2) порожденный процесс наследует приоритет родительского процесса. Если текущий приоритет привилегированного процесса не известен и требуется вернуться к стандартному приоритету, то следует последовательно обра- титься к nice с параметрами —40 (приоритет станет —20 ввиду усечения), 20 (приоритет станет нулевым) и 0 (для совместимости с ранними версиями этой системной функции). open — открыть файл на чтение или на запись OPEN(2) open(name, mode) char *name; Функция open открывает файл name на чтение (если режим mode равен 0), на запись (если mode равен 1) или и на чтение, и на запись одновременно (если mode равен 2). Параметр name представляет собой адрес цепочки литер, содержащей составное имя файла, оканчивающееся пустой литерой. Указатель текущей позиции устанавливается на начало файла (байт 0). Возвращаемый дескриптор файла может использоваться для выполнения операций над этим файлом.
Приложение 2. Системные функции 387 pause — приостановить выполнение до получения PAUSE(2) сигнала pause( ) Нормального возврата из системной функции pause не бы- вает. Она используется для возобновления выполнения после получения (ожидавшегося) сигнала от kill(2) или alarm(2). pipe — создать канал обмена данными между Р1РЕ(2) процессами pipe(fildes) int fildes[21; Системная функция pipe создает механизм ввода-вывода, на- зываемый транспортером. Возвращаемые дескрипторы файлов можно использовать для выполнения операций чтения и за- писи. Когда через дескриптор fildestl] производится запись в транспортер, буферизуется до 4096 байт данных; если места в бу- фере недостаточно, пишущий процесс приостанавливается. Чте- ние данных выполняется через дескриптор файла fildeslO]. Предполагается, что после создания транспортера два (или более) взаимодействующих процесса (созданных последующими обращениями к fork) будут передавать данные через этот тран- спортер, обращаясь к системным функциям read и write. Функция чтения read возвращает признак конца файла, если читаемый транспортер пуст и в него некому писать (все дескрип- торы для записи в этот транспортер закрыты). profil — профилирование во время выполнения PROFIL(2) profil(buff, bufsiz, offset, scale) char *buff; int bufsiz, offset, scale; Параметр buff указывает на область памяти, длина которой (в байтах) задана параметром bufsiz. После обращения к этой функции счетчик адреса (рс) программы пользователя прове- ряется через каждый временной квант (1/60 с); из него вычи- тается offset и результат умножается на scale. Если полученный номер соответствует слову внутри области памяти buff, значение этого слова увеличивается. Множитель scale интерпретируется как дробное число в дво- ичном формате с фиксированной точкой; точка расположена слева. Таким образом, 0177777(8) устанавливает взаимно одно- 13*
388 Приложение 2. Системные функции значное соответствие значений рс и слов в области buff; 077777(8) отображает каждую пару слов программы в одно и то же место. Значение 02(8) отображает все машинные команды в начало об- ласти buff (в результате в памяти программы образуется автома- тически продвигаемый таймер). Для отмены профилирования следует задать scale равным 0 или 1. Профилирование будет выполняться вхолостую, если задать bufsiz равным нулю. Кроме того, профилирование выклю- чается после выполнения системной функции ехес, но продол- жается и в порожденном, и в родительском процессах после fork. Профилирование может прекратиться, если обращение в об- ласть buff вызывает прерывание по защите памяти. read — чтение данных из файла READ(2) read(fildes, buffer, nbytes) char ^buffer; Параметр fildes — дескриптор открытого файла, buffer — адрес буфера из nbytes байт памяти, в который будут помещены считываемые данные. Не гарантируется, что будут считаны все nbytes байт памяти. Если, например, файлу соответствует тер- минал, то запрос чтения возвращает самое большее одну строку. В любом случае возвращается количество считанных литер. Если возвращается значение 0, это означает, что достигнут конец файла. setuid, setgid — установка идентификаторов пользователя и группы SETUID(2) setuid(uid) setgid(gid) Идентификатор пользователя (группы) текущего процесса устанавливается равным значению параметра. Переустанавли- ваются как эффективный, так и реальный идентификаторы. Об- ращение к этим функциям разрешается только суперпользова- телю или если значение параметра совпадает с действительным или эффективным идентификатором процесса. signal — перехват или игнорирование сигналов S1GNAL(2) ^include <signal.h> («signal(sig, func)) ( ) void (xfunc) ( );
Приложение 2. Системные функции 389 Некоторые необычные события приводят к возбуждению сиг- налов. Сигнал возбуждается либо пользователем с терминала (выход, прерывание), либо из-за программной ошибки (наруше- ние защиты и т. п.), либо по запросу другой программы (kill). Обычно все сигналы вызывают завершение работы получающего их процесса. Системная функция signal, однако, позволяет задавать либо игнорирование, либо перехват сигналов. При перехвате сигнала управление передается на заданную функцию. Список сигналов приведен в разд. 6.6.1. Если значением параметра func является SIG-DFL, для сигнала sig восстанавливается подразумеваемая реакция. Эта реакция состоит в завершении выполнения процесса, иногда с сохранением его образа памяти (дампа). Если значением func является SIG-IGN, сигнал sig в дальнейшем будет игнори- роваться. В остальных случаях при получении сигнала будет вызвана функция func с параметром — номером этого сигнала. После возврата из этой функции выполнение процесса будет продолжено с того места, где оно было прервано. За исключением сигналов 4 и 5, после перехвата состояние сигнала изменяется на подразумеваемое—SIG_DFL. Если требуется перехватывать такой, сигнал при каждом его получе- нии, подпрограмма перехвата должна еще раз обратиться к сис- темной функции signal. Некоторые системные функции завершаются преждевремен- но, не выполнив заданного действия, если во время их выпол- нения был получен перехватываемый сигнал. В частности, преждевременное завершение может произойти при выполнении ioctl, read или write(2) для медленных устройств (таких, как тер- минал, но не для дисков), а также-при выполнении pause или wait(2). В таких случаях при получении сигнала область состоя- ния процесса пользователя модифицируется таким образом, что после выполнения подпрограммы перехвата сигнала происходит возврат из системной функции с кодом ошибки. Программа поль- зователя может затем, при желании, повторить обращение к сис- темной функции. Значением, возвращаемым функцией signal, является преды- дущее (или первоначальное) значение func для данного сигнала. При выполнении fork(2) порожденный процесс наследует все состояния сигналов. Функция ехес(2) изменяет состояние всех перехватываемых сигналов на подразумеваемое. stat, fstat — получить информацию о состоянии STAT(2) файла Фinclude <sys/types.h> Ф include <sys/stat.h>
390 Приложение 2, Системные функции stat(name, buf) char *name; struct stat *buf; fstat(fildes, buf) struct stat *buf; Системная функция stat возвращает подробную информацию о состоянии файла с заданным именем. Системная функция fstat возвращает ту же самую информацию об открытом файле, задан- ном своим дескриптором. Параметр name указывает на цепочку литер, содержащую имя файла. Цепочка должна оканчиваться пустой литерой. Параметр buf представляет собой адрес буфера, в который будет помещена информация о состоянии файла. Никаких полномочий на доступ к этому файлу не требуется; необходимо, однако, иметь право на поиск во всех оглавлениях, лежащих на пути к файлу. Формат структуры, на которую указывает buf, описан в файле <sys/stat.h> и подробно рассмотрен в гл. 6. В программу следует также включить файл заголовков <sys/types.h>, содержащий все необходимые описания типов. Значениями типов ino_t, off_t и time_t являются целые раз- личной длины; в значениях типа dev_t содержатся минимальный и максимальный номера устройств. Если дескриптор файла fildes соответствует транспортеру, функция fstat выдает информацию о нем, как об обычном файле. Эта информация содержит номер индексного узла, ограниченные полномочия и необязательно осмысленную длину. Поле st_atime содержит время последнего обращения к файлу на чтение. Из соображений эффективности это поле не переуста- навливается при просмотре оглавлений, хотя это было бы логич- но. Поле st_’mtime содержит время последней записи (или соз- дания) файла. Оно не меняется при изменении владельца, груп- пы, счетчика ссылок или полномочий. Поле st_.ctime переуста- навливается как при записи в файл, так и при изменении индекс- ного узла. time, ftime — получить дату и время long time(O) long time(tloc) long *tloc; #include <sys/types.h> ^include <sys/timeb.h> ftime(tp) truct timeb *tp; TIME(2) s
Приложение 2. Системные функции 391 Функция time возвращает время в секундах, прошедшее от 00 час. 00 мин. 00 сек. 1 января 1970 года (по Гринвичу). Если tloc не равно нулю, возвращаемое значение записывается также в *tloc. При обращении к дополнительной точке входа ftime происхо- дит заполнение полей структуры, заданной параметром-указа- телем. Формат структуры описан в файле <sys/timeb.h>. Кроме упомянутого выше времени (в секундах) данная струк- тура содержит оставшиеся разряды времени (в миллисекундах), местный часовой пояс и флаг, Часовой пояс задается разницей времени (в минутах) с временем по Гринвичу; положительные значения соответствуют направлению на запад от Гринвича. Ненулевое значение флага означает, что в данной местности в со- ответствующее время года осуществляется переход на летнее время. times — получить времена выполнения процессов TIMES(2) Фinclude <sys/types.h> ^include <sys/times.h> times(buffer) struct tms «buffer; Системная функция times возвращает временные характери- стики текущего процесса и завершившихся потомков текущего процесса. Единицей измерения всех времен является 1/HZ сек., где HZ либо 50, либо 60 в зависимости от местности. Времена, затраченные порожденными процессами, являются суммой времен для прямых потомков и времен, затраченных всеми потомками этих прямых потомков. umask — установить маску прав доступа для создания файла UMASK(2) umask(complmode) Системная функция umask устанавливает маску, используе- мую при создании файла системной функцией creat(2) и командой mkdir(l). Вновь созданному файлу даются права доступа, полу- чаемые операцией логической И из прав, заданных в запросе создания, и двоичного дополнения маски — параметра функции umask. В этой операции принимают участие только младшие 9 бит маски (соответствующие битам защиты). Маска задает биты полномочий, обнуляемые при создании файла. Возвращаемым функцией umask значением является предыдущее значение маски.
392 Приложение 2. Системные функции unlink — исключить элемент из оглавления UNLINK(2) unlink(name) char *name; Параметр name указывает на цепочку литер, завершающуюся пустой литерой. Системная функция unlink удаляет элемент оглавления, соответствующий файлу, имя которого задано этой цепочкой. Если этот элемент содержал последнюю ссылку на файл, то память, занятая файлом, освобождается, и файл уничто- жается. Если, однако, этот файл был открыт каким-либо про- цессом, фактическое уничтожение файла задерживается до мо- мента его закрытия (несмотря на то что элемент оглавления удален). wait — ожидание завершения процесса WAIT(2) wait(status) int *status; wait(O) Обращение к системной функции wait вызывает задержку выполнения вызывающего процесса до тех пор, пока не будет получен какой-либо сигнал или не завершится один из порож- денных процессов этого процесса. Если со времени последнего обращения к wait хотя бы один из порожденных процессов за- вершился, возврат из функции wait выполняется немедленно. Если нет ни одного порожденного процесса, возврат также вы- полняется немедленно, но с кодом ошибки (соответственно, воз- вращаемое значение равно —1). При нормальном возврате воз- вращается идентификатор завершившегося порожденного про- цесса. Если порожденных процессов несколько, то, чтобы уз- нать об их завершении, требуется обратиться к функции wait несколько раз. Если указатель status отличен от нуля| то в старший байт слова, на которое он указывает, помещается младший байт статуса завершения порожденного процесса — параметра сис- темной функции exit. В младший байт помещается дополнитель- ная системная информация о завершении процесса. Если родительский процесс завершается, не дожидаясь за- вершения своих потомков, его потомки наследуются начальным процессом (имеющим идентификатор процесса 1). write — запись в файл write(fildes, buffer, nbytes) char *buffer; WRITE(2)
Приложение 2. Системные . функции 393 Дескриптор файла fildes — это слово, возвращаемое (при успешном завершении) системными функциями open, creat, dup и pipe. Параметр buffer содержит адрес области памяти из nbytes байт, содержимое которой требуется записать в файл. Возвращается фактическое количество записанных литер. Если оно не совпадает с запрашиваемым, это следует рассматривать как ошибку. Запись является наиболее эффективной, если она ведется бло- ками и начинается с границы блока.
ПРИЛОЖЕНИЕ 3 ПОДПРОГРАММЫ ИЗ БИБЛИОТЕКИ ЯЗЫКА С ctime, localtime, gmtime, asctime — преобразование даты и времени СТ1МЕ(3) timezone — название часового пояса char «ctime(clock) long «clock; * include <time.h> struct tm «local time(clock) long «clock; struct tm * *gmtime(clock) lonj «clock; char «asctime(tm) struct tm *tm; char *timezone(zone, dst) Параметр clock функции ctime — это указатель на перемен- ную, содержащую время в виде, получаемом при обращении к системной функции time(2). Функция ctime преобразует это время в цепочку из 26 литер в коде ASCII вида Sun Sep 16 01:03:52 1973\п\0 (Воскресенье, Сентябрь, 16 01:03:52 1973) и возвращает указатель на эту цепочку. Размер всех полей в це- почке фиксирован. Функции local time и gmtime представляют дату и время в виде структуры и возвращают указатель на эту структуру. Функция localtime корректирует время в соответствии с местным часовым поясом, учитывая также и летнее время, a gmtime преобразует время непосредственно в среднее время по Гринвичскому мери- диану (GMT), которое и используется в системе UNIX. Функция
Приложение 3. Подпрограммы из библиотеки языка С 395 asctime преобразует представленное в виде структуры время в це- почку из 26 литер в коде ASCII и возвращает указатель на эту цепочку. Описание используемой в этих функциях структуры содер- жится в файле заголовков time.h и имеет вид struct tm { /* смотрите dime (3) */ int tm_sec; /* секунды *7 int tm_min; /* минуты */ int tm.hour; 7* часы */ int tm_mday; 7* день месяца */ nt tm_mon; /* месяц *7 int tm.year; 7* год */ int tm_wday; 7* день недели *7 int tm_yday; /* день года */ }; >nt tm_isdst; 7* летнее время Поля этой структуры содержат время суток по 24-часовой шкале, день месяца (1—31), месяц года (0—11), день недели (О означает воскресенье), год минус 1900, день года (0—365) и флаг, который отличен от нуля, если действует летнее время. Для определения местного времени программа localtime узнает у системы часовой пояс и выясняет, действует ли в дан- ной местности принятое в США соглашение о переходе на летнее время. Программа знает об особенностях перехода на летнее время в 1974 и 1975 годах; в случае необходимости таблица для таких особых годов может быть расширена. Функция timezone возвращает название часового пояса, соответствующее первому параметру, значение которого за- дается в минутах в направлении на запад от Гринвичского ме- ридиана. Если второй параметр равен нулю, используется стан- дартное название, в противном случае используется название, учитывающее летнее время. Если в таблице, встроенной в функ- цию timezone, нет требуемого названия, то результатом будет разница по времени относительно Гринвичского среднего вре- мени. Например, для Афганистана обращение к этой функции имело бы вид timezonef—(60*4+30), 0), так как время там на 4 часа 30 минут опережает Гринвичское среднее время. Резуль- татом будет цепочка литер GMT+4:30. fclose, fflush — закрыть поток или вытолкнуть FCLOSE(3S) содержимое буферов потока вывода 4|=include <stdio.h> fclose(stream) FILE *stream;
396 Приложение 3. Подпрограммы из библиотеки языка С ff lush (stream) FILE «stream; Функция fclose очищает все буфера, используемые указанным потоком stream, и закрывает связанный с этим потоком файл. Буфера, выделенные для данного потока стандартной системой ввода-вывода, освобождаются. Функция fclose вызывается авто- матически при выполнении функции exit(2). Функция fflush записывает все данные, накопленные в буфере указанного потока вывода stream, в связанный с этим потоком файл. Поток остается открытым. Эти функции возвращают EOF, если поток stream не связан ни с каким файлом или если буферизованные данные не удается переслать в файл. feof, ferror, clearerr, fileno — информация о состоянии потока FERROR(3S) ^include <stdio.h> feof(stream) FILE «stream; ferror(stream) FILE «stream; clearerr(stream) FILE «stream; fileno(stream) FILE «stream; Функция feof возвращает ненулевой код ответа, если из ука- занного потока ввода stream считан признак конца файла; в про- тивном случае возвращается нуль. Функция ferror возвращает ненулевой код ответа, если при чтении или записи в заданный поток stream произошла ошибка; в противном случае возвращается нуль. Индикация об ошибке (если только она не сброшена функцией clearerr) возвращается до тех пор, пока данный поток не будет закрыт. . Функция clearerr сбрасывает индикацию ошибки для указан- ного потока stream. Функция fileno возвращает целочисленный дескриптор файла, с которым связан поток stream. Эти функции реализованы в виде макроопределений и не мо- гут быть переопределены.
Приложение 3. Подпрограммы из библиотеки языка С 397 fopen, freopen, fdopen — открыть поток FOPEN(3S) 4(=include <stdio.h> FILE *fopen(filename, type) char «filename, «type; FILE «freopen(filename, type, stream) char «filename, «type; FILE «stream; FILE «fdopen(fildes, type) char «type; Функция fopen открывает файл с именем filename и связывает с ним поток. Указатель, возвращаемый функцией fopen, исполь- зуется для идентификации потока в последующих операциях. Второй параметр (тип) — цепочка литер, имеющих одно из сле- дующих значений: г Открыть на чтение. w Создать и открыть на запись. а Открыть на дозапись в конец файла или создать и открыть на запись. Функции fopen и freopen возвращают нулевой указатель NULL, если файл с именем filename не может быть открыт в ука- занном режиме. Кроме того, за буквами г, w и а в типе может следовать знак +, что означает открытие файла и на чтение, и на запись одновре- менно. По г+р указатель чтения-записи устанавливается на на- чало файла, по w+ файл создается или обрезается, а по а+ вы- полняется установка на конец файла. Над такими потоками мож- но выполнять и операций чтения, и операции записи при том ограничении, что при переходе от чтения к записи (и наоборот) должна выполняться функция fseek или rewind либо должен встре- титься конец файла. Функция freopen связывает уже открытый поток stream с дру- гим файлом (с именем filename). Возвращается исходное значение stream. Файл, с которым до этого был связан поток, закры- вается. Функция freopen часто используется для того, чтобы связать заданные файлы со стандартными заранее открытыми потоками stdin, stdout и stderr. Функция fdopen связывает поток с дескриптором файла fildes, полученным в результате выполнения одной из системных функ- ций open, dup, creat или pipe(2). Тип потока (параметр type) должен соответствовать режиму, в котором был открыт данный файл.
398 Приложение 3. Подпрограммы из библиотеки языка С fread, fwrite— бесформатный ввод-вывод с FREAD(3S) буферизацией ^include <stdio.h> fread(ptr, sizeof(*ptr), nitems, stream) FILE *stream; fwrite(ptr, sizeof(*ptr), nitems, stream) FILE «stream; Функция fread из заданного потока ввода stream считывает nitems элементов данных типа *ptr в область памяти, на начало которой указывает указатель ptr. Возвращается фактическое число считанных элементов. Функции fread и fwrite возвращают нуль при достижении конца файла или обнаружении ошибки. Если задан поток stdin, а в потоке стандартного вывода осу- ществляется построчная буферизация, то при выполнении fread перед обращением к системной функции read(2) содержимое буфера выталкивается в файл стандартного вывода. Функция fwrite дозаписывает максимум nitems элементов дан- ных типа *ptr из области памяти, на начало которой указывает указатель ptr, в заданный поток вывода stream. Она возвращает фактическое число записанных элементов данных. fseek, ftell, rewing—изменение текущей позиции FSEEK(3S) чтения-записи для потока ^include <stdio.h> fseek(stream, offset, ptrname) FILE *stream; long offset; long ftell(stream) FILE *stream; rewind (stream) Функция fseek переустанавливает текущую позицию для по- тока stream. Следующая операция чтения-записи будет выпол- няться с этой новой позиции. Новая текущая позиция устанавли- вается на расстоянии offset байт от начала файла, старой текущей позиции или конца файла в зависимости от значения параметра ptrname (0,1 или 2 соответственно). Функция fseek аннулирует действие ungetc(3S). Функция ftell возвращает текущее значение смещения (в бай- тах) относительно начала файла, связанного с заданным потоком
Приложение 3. Подпрограммы из библиотеки языка С 399 stream. Это единственный надежный способ получения величины offset для функции fseek. Функция установки на начало rewind(stream) эквивалентна fseek(stream, 0L, 0). При неправильной установке fseek возвращает значение —1. getc, getchar, fgetc, getw—получить литеру или GETC(3S) слово из потока ^include <stdio.h> int getc(stream) FILE «stream; int getcharf ) int fgetc(stream) FILE «stream; int getw(stream) FILE «stream; Функция getc возвращает очередную литеру из указанного потока ввода stream. Функция getchar( ) эквивалентна getc(stdin). Функция fgetc аналогична getc, но является действительно функцией, а не макроопределением. Функция getw возвращает из указанного потока ввода stream очередное слово (на VAX 11—32-разрядное целое). При дости- жении конца файла или при возникновении ошибки getw воз- вращает константу EOF. Так как эта константа является целым числом, то для проверки на успешное завершение следует ис- пользовать feof и ferror(3). Выравнивание по границе слова в файле не производится. При достижении конца файла или при возникновении ошибки эти функции возвращают EOF. При попытке читать из потока, не открытого на чтение функ- цией fopen, происходит останов с сообщением Reading bad file (Некорректное чтение). getenv — значение переменной среды GETENV(3) extern char ««environ; char «getenv(name) char «name; Функция getenv просматривает список переменных среды в поисках цепочки вида имя=значение, где имя задано парамет-
400 П риложение 3. Подпрограммы из библиотеки языка С ром name, и возвращает соответствующее значение, если такая цепочка обнаружена, и нуль в противном случае. Внешняя переменная environ указывает на массив цепочек литер, называемый средой. Среда передается процессу при вы- полнении системной функции ехес(2), т. е. когда процесс начи- нает выполнять новую программу. По соглашению, цепочки, из которых состоит среда, имеют вид имя=значение. Новые переменные помещаются в среду при помощи команды export или ключевых параметров вида имя=значение языка-обо- лочки sh(l). Кроме того, это можно сделать в момент выполнения ехес(2). gets, fgets— получить цепочку из потока GETS(3S) ^include <stdio.h> char *gets(s) char *s; char *fgets(s, n, stream) char *s; FILE *stream; Функция gets считывает в s цепочку литер из стандартного потока ввода stdin. Цепочка заканчивается литерой новой строки, которая заменяется в s пустой литерой. Возвращаемым значе- нием является значение параметра s (адрес цепочки). Функция fgets считывает в s из потока stream цепочку вплоть до литеры новой строки, но не более n—1 литер. За последней считанной bs литерой помещается пустая литера. Возвращаемым значением является значение первого параметра (адрес цепочки). При достижении конца файла или в случае возникновения ошибки функции gets и fgets возвращают константу-указатель NULL. malloc, free, realloc, calloc — распределение оперативной памяти char *malloc(size) unsigned size; free(ptr) char *ptr; char *realloc(ptr, size) char *ptr; unsigned size; char *calloc(nelem, elsize) unsigned nelem, elsize; MALLOC(3)
Приложение 3. Подпрограммы из библиотеки языка С 401 Эти функции представляют собой простой пакет распределе- ния памяти, предназначенный для широкого использования. Функция malloc возвращает указатель на блок памяти, со- стоящий по крайней мере из size байт и начинающийся с границы слова. Параметром функции free должен быть указатель на блок па- мяти, ранее выделенный функцией malloc. Содержимое блока остается неизменным, но сам блок включается в список свобод- ного пространства и может быть выделен при последующих запросах malloc. Само‘собой разумеется, что запись за пределы блока, выде- ленного malloc, также как и обращение к free со случайным ука- зателем в качестве параметра, может привести к тяжелым по- следствиям. Функция malloc циклически просматривает блоки свободного пространства и выделяет первый свободный блок достаточно большого размера. Просмотр начинается с последнего выделен- ного или освобожденного блока. Соседние блоки свободного про- странства при просмотре сливаются в один. Если блока подходя- щего размера не оказалось, при помощи системной функции sbrk (см. break(2)) у системы запрашивается дополнительная память. Функция realloc изменяет размер блока, на который указыва- ет ptr, делая его равным size байт, и возвращает указатель на этот (возможно, передвинутый в другое место) блок. Содержимое блока (вплоть до границы, соответствующей, минимальному из двух размеров — старому и новому) остается прежним. При обращении к функции realloc параметр ptr может также указывать на блок, который был освобожден со времени послед- него обращения к malloc, realloc или calloc. Это позволяет вы- полнять уплотнение памяти, учитывая стратегию поиска свобод- ного пространства, используемую в malloc, при последовательных обращениях к free, malloc и realloc. Функция calloc отводит область памяти под массив из nelem элементов размером elsize байт каждый. Этот массив запол- няется нулями. Все подпрограммы распределения памяти возвращают указа- тель на область памяти, выровненную таким образом, что в нее можно поместить объект любого типа. Функции malloc, realloc и calloc возвращают нулевой ука- затель (0) в случае, если не осталось свободной памяти или если обнаружилось, что используемые в этих подпрограммах данные пострадали из-за записи за пределы отведенных бло- ков. В случае если realloc возвращает 0, блок, на который указы- вал параметр ptr, может оказаться разрушенным. 14 С. Баурн
402 Приложение 3. Подпрограммы из библиотеки языка С mktemp — создание уникального имени для МКТЕМР(З) файла char *mktemp(template) char ^template; Функция mktemp заменяет шаблон template уникальным име- нем файла и возвращает адрес этого шаблона. Шаблон должен содержать имя файла, оканчивающееся шестью буквами X, которые будут заменены идентификатором текущего процесса и уникальной буквой. monitor — подготовить профиль выполнения MONITOR(3) monitor(lowpc, highpc, buffer, bufsize, nfunc) int (*lowpc)( ), (*highpc)( ); short bufferi ]; В готовую программу, полученную при помощи команды сс—р, автоматически включаются обращения к функции monitor с подразумеваемыми параметрами. Явно обращаться к функции monitor не требуется, за исключением случая, когда желательно более точное управление процессом профилирования. Функция monitor является интерфейсом для’системной функ- ции profi 1 (2). Параметры lowpc и highpc — адреса двух функций; buffer — адрес (подготовленного пользователем) массива из bufsize коротких целых. Функция monitor обеспечивает построе- ние гистограммы для периодически замеряемых значений счетчика адреса и подсчет числа обращений к определенным функциям. Эта информация накапливается в массиве buffer. Значения счет- чика адреса контролируются в диапазоне от lowpc до highpc, включая lowpc, но исключая highpc. Максимальное число счет- чиков обращений к функциям равно nfunc; подсчитываются толь- ко обращения к функциям, скомпилированным с опцией —р команды сс(1). Чтобы результаты профилирования имели смысл, размер буфера должен быть меньше диапазона контролируемых значений счетчика адреса не более чем в несколько раз (особен- но при наличии коротких интенсивно используемых подпро- грамм). perror, sys_errlist, sys_nerr—системные сообщения PERROR(3) об ошибках perror(s) char *s; extern int sys_nerr; extern char *sys_errlist[ ];
Приложение 3. Подпрограммы из библиотеки языка С 403 Функция реггог выдает в стандартный файл диагностики ко- роткое сообщение о последней ошибке, возникшей при обраще- нии из С-программы к системной функции. Сначала печатается цепочка-параметр s, затем — двоеточие, собственно сообщение об ошибке и литера новой строки. В качестве цепочки-параметра наиболее часто используется имя программы, в которой возник- ла ошибка. Код ошибки берется из внешней переменной еггпо; эта переменная устанавливается при возникновении ошибки, но не обнуляется при успешном завершении системных функций. Для обеспечения вывода сообщений об ошибках в различных форматах предоставляется вектор сообщений sys__errlist; чтобы получить сообщение о последней ошибке (без литеры новой стро- ки), можно использовать еггпо в качестве индекса в этой таблице. Число сообщений, включенных в таблицу, содержится в пере- менной sys_nerr. Новые коды ошибок могут добавляться в сис- тему раньше, чем сообщения об этих ошибках будут занесены в таблицу, поэтому следует проверять, не выходит ли индекс (еггпо) за пределы sys.nerr. popen, pclose — организовать обмен данными с другим процессом POPEN(3S) ^include <stdio.h> FILE «popen (command, type) char «command, «type; pclose(stream) FILE «stream; Параметрами функции popen являются указатели на цепочки литер, оканчивающиеся пустой литерой, содержащие соответст- венно командную строку оболочки и режим ввода-вывода (г — чтение, w — запись). Функция popen инициализирует указанную команду и создает транспортер между нею и вызывающим про- цессом. Возвращается указатель на поток. Этот указатель можно использовать (в зависимости от режима) для записи в файл стан- дартного ввода инициализированной команды или чтения из ее файла стандартного вывода. Поток, открытый функцией popen, должен быть закрыт функ- цией pclose. Функция pclose ожидает завершения соответствую- щего процесса и возвращает статус завершения команды. Поскольку открытые файлы являются разделяемыми, коман- ду типа г можно использовать как входной фильтр, а команду типа w — как выходной фильтр. Функция popen возвращает NULL, если ей не удается создать файл или процесс или если не доступна оболочка. 14*
404 Приложение 3. Подпрограммы из библиотеки языка С Функция pclose возвращает —1, если указанный поток не был открыт при помощи рореп. printf, fprintf, sprintf — форматный вывод PRINTF(3S) ^include <stdio.h> printf(format [ , arg ] ...) char «format; fprintf(stream, format [ , arg ] ...) FILE «stream; char «format; sprintf(s, format [ , arg ] ...) char *s, format; Функция printf помещает данные в стандартный поток вывода stdout. Функция fprintf помещает данные в указанный поток вы- вода stream. Функция sprintf записывает данные в цепочку s, завершая их пустой литерой. Каждая из этих функций преобразует, форматирует и печа- тает свои второй и последующие параметры в соответствии с пер- вым параметром. Первый параметр (формат) представляет собой цепочку литер, содержащую объекты двух типов: обычные лите- ры, которые просто копируются в поток вывода, и спецификации преобразований, каждая из которых вызывает преобразование и печать очередного параметра функции printf. Спецификация преобразования начинается с литеры %, за которой может следовать: • Необязательный знак минус, который задает выравнива- ние преобразованного значения по левому краю занимае- мого им поля. • Необязательная последовательность цифр, задающая ши- рину поля. Если преобразованное значение ’состоит из меньшего числа литер, чем указанная ширина поля, зна- чение дополняется пробелами слева (или справа, если задано выравнивание по левому краю) до этой ширины. Если первой цифрой числа, задающего ширину поля, является нуль, то оставшиеся позиции будут заполняться нулями. • Необязательная точка, отделяющая ширину поля от следующей последовательности цифр. • Необязательная последовательность цифр — точность, которая задает число цифр, печатаемых после десятичной точки для преобразований е и f, или максимальное число печатаемых литер в случае спецификации s.
Приложение 3. Подпрограммы из библиотеки языка С 405 • Буква I указывает, что следующие преобразования d, о, х или и будут выполняться над параметром типа длин- ное целое. (Тот же смысл имеют преобразования, заданные прописными буквами D, О, X и U.) • Литера, определяющая тип преобразования. Вместо последовательности цифр для указания ширины поля или точности можно задавать литеру *. В этом случае ширина поля или точность берутся из следующего целочисленного пара- метра. Ниже приводятся литеры, определяющие тип преобразований и их смысл. В любом случае, однако, опущенная или недостаточ- ная ширина поля не приводит к обрезанию преобразованного значения; дополнение до ширины поля выполняется только тог- да, когда фактическая длина выводимой цепочки меньше ширины поля. Литеры, сгенерированные функцией printf, печатаются функцией putc(3). dox Параметр целого типа преобразуется соответственно к десятичному, восьмеричному или шестнадцатерич- ному виду. f Параметр типа float или double преобразуется в деся- тичное представление вида [—iddd.ddd, где число литер d после десятичной точки равно заданной для этого параметра точности. Если точность не задана, выводятся 6 цифр. Если задана точность 0, дроб- ная часть и десятичная точка не печатаются. е Параметр типа float или double преобразуется к виду I—]d.ddde±dd, где перед десятичной точкой выводится только одна цифра, а число цифр после точки равно заданной для этого параметра точности. Если точ- ность не задана, выводятся 6 цифр. g Параметр типа float или double печатается в том из форматов d, f или е, который обеспечивает наибольшее число значащих цифр при минимальной ширине поля. с Печатается параметр типа char (одна литера). s Параметр считается цепочкой литер (указателем на переменную типа char). Литеры из этой цепочки пе- чатаются до тех пор, пока не встретится пустая литера или пока не будет напечатано количество литер, за- данное спецификацией точности. Если, однако, точ- ность не задана или равна нулю, печатаются все ли- теры вплоть до пустой. и Беззнаковый целый параметр преобразуется к деся- тичному виду и печатается (результат будет лежать в диапазоне от 0 до MAXUINT, где MAXUINT равно 4294967295 для VAX 11 и 65535 для PDP И).
406 Приложение 3. Подпрограммы из библиотеки языка С % Печать самой литеры %; ни один параметр не преобра- зуется. putc, putchar, fputc, putw — поместить литеру или слово в поток PUTC(3S) ^include <stdio.h> int putc(c, stream) char c; FILE «stream; putchar(c) fputc(c, stream) FILE «stream; putw(w, stream) FILE «stream; Функция putc дозаписывает литеру с в указанный поток вывода stream и возвращает записанную литеру. Функция putchar(c) определяется как putc(c, stdout). Функция fputc выполняет те же действия, что и putc, однако является действительно функцией, а не макроопределением. Функция putw дописывает слово w (значение типа int) в поток вывода stream и возвращает записанное слово. Функция putw не требует и не выполняет выравнивание по границе слова в выходном файле. Стандартный поток stdout обычно буферизуется тогда и только тогда, когда он не связан с терминалом; это подразумеваемое поведение можно изменить с помощью функции setbuf(3S). Стандартный поток stderr по умолчанию не буферизуется не- зависимо от выходного файла, однако буферизация включается при использовании функции freopen. Функция setbuf позволяет по желанию включать или выключать буферизацию. Если поток вывода не буферизуется, информация появляется в целевом фай- ле или на терминале сразу после записи; если же буферизация выполняется, литеры накапливаются и записываются блоками. Чтобы записать блок до его полного заполнения, можно восполь- зоваться функцией fflush. В случае ошибки все рассматриваемые функции возвращают константу EOF. Поскольку эта константа является целым чис- лом, для распознавания ошибочных ситуаций в случае функции putw следует использовать функцию terror.
Приложение 3. Подпрограммы из библиотеки языка С 407 puts, fputs — записать цепочку литер в поток PUTS(3S) ^include <stdio.h> puts(s) char *s; fputs(s, stream) char *s; FILE ^stream; Функция puts копирует цепочку s, заканчивающуюся пустой литерой, в стандартный поток вывода stdout, добавляя к ней литеру новой строки. Функция fputs копирует цепочку s, заканчивающуюся пустой литерой, в заданный поток вывода stream. Ни одна из этих функций не копирует завершающую пустую литеру. scanf, fscanf, sscanf — форматный ввод SCANF(3S) ^include <stdio.h> scanf(format [ , pointer ] ... ) char *format; fscanf(stream, format [ , pointer ] ... ) FILE ^stream; char ^format; sscanf(s, format [ , pointer ] ... ) char *s, *format; Функция scanf читает стандартный поток ввода stdin. Функ- ция fscanf читает заданный поток ввода stream. Функция‘sscanf читает литеры из цепочки s. Каждая из этих функций считывает литеры, интерпретирует их согласно формату и записывает ре- зультаты в переменные,задаваемые вторым и последующими параметрами. Параметрами всех этих функций являются управ- ляющая цепочка format (формат), описываемая ниже, и набор указателей, определяющих, куда следует поместить преобразо- ванные данные. Управляющая цепочка может содержать спецификации пре- образований, которые используются для интерпретации входных последовательностей литер. Управляющая цепочка может со- держать: • Пробелы, табуляции и литеры новой строки, которые сопоставляются с необязательными пропусками во вводе.
408 Приложение 3. Подпрограммы из библиотеки языка С • Обычные литеры (кроме %), которые должны совпадать с очередными литерами из потока ввода. • Спецификации преобразования, начинающиеся с литеры %, за которой могут следовать необязательная литера подавления * и необязательное число, задающее макси- мальную ширину поля. Спецификация заканчивается литерой преобразования. Спецификация преобразования управляет преобразованием очередного входного поля. Результат помещается в переменную, на которую указывает соответствующий параметр-указатель (если только не задана литера подавления присваивания *). Входное поле определяется как цепочка литер, отличных от пробелов, табуляций и литер новой строки. Оно продолжается либо до пер- вой неподходящей для данного преобразования литеры, либо до исчерпания ширины поля, если она задана. Литера преобразования определяет интерпретацию входного поля. Соответствующий параметр-указатель должен указывать на переменную соответствующего данному преобразованию типа. Допускаются следующие литеры преобразования: % В данном месте входного файла ожидается одиночная литера %. Присваивание не выполняется. d Ожидается десятичное целое. Соответствующий пара- метр должен быть указателем на целое. о Ожидается восьмеричное целое. Соответствующий параметр должен быть указателем на целое. х Ожидается шестнадцатеричное целое. Соответствую- щий параметр должен быть указателем на целое. s Ожидается цепочка литер. Соответствующий параметр должен указывать на массив литер, который достато- чен для хранения вводимой цепочки и добавляемой к ней пустой литеры (\0). Входное поле заканчива- ется пробелом или литерой новой строки. с Ожидается одна литера. Соответствующий параметр должен быть указателем на литеру. Пропуск пробе- лов, табуляций и литер новой строки в этом случае не выполняется. Для чтения следующей литеры, от- личной от пробела, табуляции и новой строки, поль- зуйтесь спецификацией % 1s. Если задана ширина поля, соответствующий параметр должен указывать на массив литер; в этом случае считывается заданное число литер. е Ожидается число с плавающей точкой. Очередное поле f преобразуется соответствующим образом. Результат запоминается в переменной, на которую указывает соответствующий параметр. Этот параметр должен
Приложение 3. Подпрограммы из библиотеки языка С 409 быть указателем на переменную типа float. Входной формат для числа с плавающей точкой включает в себя необязательный знак, последовательность цифр, воз- можно содержащую десятичную точку и необязатель- ное поле порядка, состоящее из литеры Е или е и це- лого числа (возможно, со знаком). [ Вводит цепочку литер, которая не ограничивается пробелом, табуляцией или литерой новой строки. За левой квадратной скобкой следуют последователь- ность литер и правая квадратная скобка. Литеры между квадратными скобками определяют множество литер, из которых может состоять вводимая цепочка. Если первая литера не л, входным полем будет вся последовательность входных литер до первой литеры, не встречающейся в квадратных скобках. Если же первой литерой после левой квадратной скобки яв- ляется Л, то входным полем считается вся последо- вательность литер вплоть до первой литеры из мно- жества остальных литер в квадратных скобках. Со- ответствующий параметр должен быть указателем на массив литер. Вместо спецификаций d, о и х можно использовать специфи- кации D, О и X или Id, to и lx. Это означает, что в списке пара- метров задан указатель на переменную типа long, а не int. Ана- логично вместо спецификаций е и f можно использовать специфи- кации Е и F или 1е и If. Это означает, что задан указатель на переменную типа double, а не float. Перед спецификациями d, о и х можно помещать букву h, что означает задание указателя на переменную типа short вместо int. Функции семейства scant возвращают число успешно сопо- ставленных и присвоенных заданным переменном входных эле- ментов данных. Это число можно использовать для определения количества введенных полей. При достижении конца файла ввода возвращается константа EOF. Заметим, что это значение отлично от нуля, который означает, что не выполнено ни одного преобразования. Предполагавшееся преобразование может не выполниться из-за ввода неподходящей литеры. Функции семейства scanf возвращают EOF при достижении конца файла ввода и число, меньшее ожидаемого, в случае от- сутствия или неправильного задания входных элементов данных. setbuf — задать буфер для потока SETBUF(3S) ^include <stdio.h>
410 Приложение 3. Подпрограммы из библиотеки языка С setbuf(stream, but) FILE *stream; char *buf; Функция setbuf вызывается после открытия потока, но перед выполнением операций чтения или записи. После обращения к setbuf вместо автоматически выделяемого буфера будет использо- ваться массив литер buf. Если значением buf является константа- указатель NULL, операции ввода-вывода будут выполняться без буферизации. Требуемый размер массива определяется константой BUFSIZ: char buf[BUFSIZ]; Буфер для данного потока обычно запрашивается при помощи функции malloc(3) при первом обращении к getc или putc(3). Исключение составляет поток стандартного вывода, в котором, когда он связан с терминалом, осуществляется построчная буфе- ризация. Остальные потоки вывода, связанные с терминалами, и поток стандартной диагностики обычно не буферизуются. Если в потоке стандартного вывода осуществляется построчная буфе- ризация, то содержимое буфера выталкивается в файл всякий раз, когда при помощи read(2) выполняется чтение из файла стандартного ввода. setjmp, longjmp — нелокальный переход . SETJMP(3) ^include <setjmp.h> setjmp(env) jmp_buf env; longjmp(env, val) jmp_buf env; Эти подпрограммы полезны для обработки ошибок и преры- ваний в подпрограммах нижнего уровня разветвленной про- граммы. Подпрограмма setjmp сохраняет состояние стека в переменной env для последующего использования подпрограммой longjmp. Возвращаемым значением является нуль. Подпрограмма longjmp восстанавливает из переменной env состояние стека, сохраненное при последнем обращении к setjmp. Возврат из setjmp осуществляется таким образом, что при этом выполнение программы возобновляется, как если бы подпрограм- ма setjmp вернула значение val в функцию, из которой она была вызвана. К этому времени еще не должно быть возврата из функ-
Приложение 3. Подпрограммы из библиотеки языка С 411 ции, из которой была вызвана setjmp. Все доступные переменные имеют значения, которые они имели в момент обращения к longjmp. stdio — стандартный пакет ввода-вывода с буферизацией STDIO(3S) Фinclude <stdio.h> FILE «stdin; FILE «stdout; FILE «stderr; Стандартная библиотека ввода-вывода описана в гл. 5. strcat, strncat, strcmp, strncmp, strcpy, strncpy, strlen, index, rindex — операции над цепочками литер STRING(3) char *strcat(sl, s2) char »sl, *s2; char *stmcat(sl, s2, n) char *sl, «s2; strcmp(sl, s2) char *sl, *s2; stmcmp(sl, s2, n) char *sl, *s2; char »strcpy(sl, s2) char *sl, »s2; char *strncpy(sl, s2, n) char *sl, *s2; strlen(s) char »s; char *index(s, c) char *s, c; char *rindex(s, c) char »s, c; Эти функции выполняют операции над цепочками, заканчи- вающимися пустой литерой. Проверка на переполнение получае- мых цепочек не производится. Функция strcat дописывает копию цепочки s2 в конец цепоч- ки si. Функция strncat копирует не более п литер. Обе эти функ-.
412 Приложение 3. Подпрограммы аз библиотеки языка С ции возвращают указатель на результирующую цепочку, закан- чивающуюся пустой литерой. Функция strcmp сравнивает свои параметры-цепочки si и s2 и возвращает положительное целое число, нуль или отрицатель- ное целое число, если si лексикографически больше, равна или меньше, чем s2. Функция strncmp выполняет такое же сравнение, однако сравнивается не более и литер. Функция strcpy копирует цепочку s2 в si. Копирование за- канчивается после переписи пустой литеры. Функция stmcpy копирует ровно и литер, обрезая s2 или дополняя ее пустыми литерами. Если длина цепочки s2 больше или равна п литер, в конце результирующей цепочки si пустой литеры может не ока- заться. Обе функции возвращают si. Функция strlen возвращает число литер, содержащихся в це- почке s (пустая литера в это число не включается). Функции index и rindex возвращают указатели соответственно на первое и последнее вхождение литеры с в цепочку s или нуль, если с не содержится в этой цепочке. ungetc — вернуть литеру в поток ввода UNGETC(3S) #include <stdio.h> ungetc(c, stream) FILE «stream; Функция ungetc возвращает литеру с назад в поток ввода. Эта литера будет считана при следующем обращении к getc. Резуль- татом функции ungetc является литера с. Возможность вернуть в поток ввода одну литеру гаранти- руется при условии, что поток буферизован и из него уже были прочитаны какие-либо литеры. Попытки вернуть EOF отвер- гаются. Функция fseek(3) аннулирует все возвращаемые в поток ли- теры. Функция ungetc возвращает EOF, если литеру нельзя помес- тить обратно в поток.
ПРИЛОЖЕНИЕ 4 ЗАПРОСЫ ОТЛАДЧИКА adb Форматная печать файлов ^формат Печать содержимого файла a.out в соответствии с заданным форматом. 1формат Печать содержимого файла core в соответствии с заданным форматом. =формат Печать значения текущего адреса. ?w выражение Запись выражения в файл a.out. /w выражение Запись выражения в файл core. ?! выражение Определение местонахождения выражения в файле a.out. Контрольные точки и управление программой :Ь Установить контрольную точку по текущему адресу. :с Продолжить выполнение программы. :d Снять контрольную точку. :к Прекратить выполнение отлаживаемой программы. :г Начать выполнение программы a.out под управ- лением отладчика. :s Выполнять программу в пошаговом режиме, Печать отладочной информации $Ь Печать текущих контрольных точек. $с Трассировка стека. $е Печать значений внешних переменных. $f Печать регистров с плавающей точкой. $т Печать карт памяти. $q Выход из отладчика. $г Печать регистров общего назначения. $s Задать смещение для символа. $v Печать значений переменных отладчика. $w Установить длину выводимой строки.
414 Приложение 4. Запросы отладчика adb Разное ! Выполнить команду оболочки. >имя Занести текущий адрес в переменную или регистр с заданным именем. Сводка форматов а b с d f i о n г s nt Текущий адрес. Один байт в восьмеричном виде. Один байт в литерном виде. Одно слово в десятичном виде. Два слова как число с плавающей точкой. Машинная команда. Одно слово в восьмеричном виде. Новая строка. Пробел. Цепочка литер, заканчивающаяся литерой \0. Перейти к следующей позиции табуляции; п — ин- тервал табулирования. u X Y A Г/ V Одно слово в виде целого без знака. Печать в шестнадцатеричном виде. Печать даты. Возврат к предыдущему элементу. Печать цепочки литер. Операнды выражений десятичное целое Пример: 256 восьмеричное целое Пример: 0277 шестнадцатеричное целое Пример: =||=ff символы Примеры: flag, main ma in. аг go переменные Пример: <b регистры Примеры: <рс <г0 (выражение) Группировка выражений. Бинарные операции Эти операции имеют одинаковый приоритет и выполняются слева направо. + * % & Сложение. Вычитание. Умножение. Целочисленное деление. Поразрядное логическое И. 1 Поразрядное логическое’ИЛИ. Округление до ближайшего кратного.
Приложение 4. Запросы отладчика adb 415 Унарные операции НЕ — логическое отрицание. * Содержимое по заданному адресу в файле core. Содержимое по заданному адресу в файле a.out. Унарный минус.
ПРИЛОЖЕНИЕ 5 ЗАПРОСЫ РЕДАКТОРА ed Запросы а Вставить текст после текущей строки. с Заменить указанные строки. d Исключить текущую строку. е Начать редактирование файла с заданным именем, проверив, что старое содержимое буфера записано в файл. Е Начать редактирование файла без проверки. f Напечатать имя редактируемого файла. g Применить указанный запрос ко всем строкам, со- держащим заданный образец. i Вставить текст перед текущей строкой. j Объединить строки. к Пометить строку. I Напечатать строку. Неграфические литеры вы- водятся в графическом представлении. m Переставить группу строк в другое место. п Напечатать строки вместе с их номерами. р Напечатать строки. q Выйти из редактора, проверив, что содержимое бу- фера записано в файл. Q Выйти без проверки. г Считать файл в буфер. s Заменить текст в пределах строки. t Скопировать группу строк. и Аннулировать результат выполнения последнего запроса замены s. v Применить указанный запрос ко всем строкам, не содержащим заданный образец. w Записать группу строк в файл. W Дозаписать группу строк в конец файла. « Напечатать номер строки.
Приложение 5. Запросы редактора ed 417 ! + Выполнить системную команду. Сделать шаг вперед на одну строку. Сделать шаг назад на одну строку. Выражения isj [Л«] е* \(*\) Любая литера, кроме новой строки. Любая литера из цепочки s. Любая литера, не входящая в цепочку s. Все соседние вхождения е. Выделить подвыражение. На подвыражение можно ссылаться, используя конструкцию \п. \п Л $ \С п-е выделенное подвыражение. Начало строки. Конец строки. Отменить специальное значение литеры с. Адреса Текущая .строка. п $ 'х № ?е? а±п а± n-я строка. Последняя строка редактируемого текста. Строка, помеченная меткой х. Ближайшая следующая строка, содержащая е. Ближайшая предшествующая строка, содержащая е. Адрес ±п. а ± 1.
ПРИЛОЖЕНИЕ 6 командный язык Синтаксис элемент: слово ввод-вывод имя=значение простая-команда: элемент простая-команда элемент команда: простая-команда ( список-команд ) { список-команд } for имя do список-команд done for имя in слово ... do список-команд while список-команд do список-команд until список-команд do. список-команд case слово in вариант . . . esac if список-команд then список-команд else-i fi done done done часть конвейер! команда конвейер | команда и-или: конвейер и-или && конвейер и-или || конвейер список-команд: и-или список-команд; список-команд & список-команд ; и-или список-команд & и-или ввод-вывод! > файл < файл
Приложение 6. Командный язык 419 >> слово < <слово файл: слово & цифра & — вариант: образец ) список-команд ;; образец: слово образец | слово else-часть: elif список-команд then список-команд else-часть else список-команд пусто пусто: слово: последовательность литер, отличных от про- бела, табуляции и новой строки имя: последовательность букв, цифр и символов подчеркивания, начинающаяся с буквы цифра: 0123456789 Синтаксические символы | Символ транспортера (для соединения команд в кон- вейер). && II Символ «и». Символ «или». Разделитель команд. Разделитель вариантов. & о Фоновые команды. Группирование команд. Переадресация ввода. Ввод текста из встроенного документа. Переадресация вывода (создание файла вывода). Добавление вывода в конец файла. Образцы * Сопоставляется с любой цепочкой литер, включая и пустую. ? [...] Сопоставляется с любой одиночной литерой. Сопоставляется с любой из литер, заключенных в скобки.
420 Приложение 6. Командный язык Подстановка ${...} Подстановка переменной оболочки. Подстановка вывода команды. Соглашения об отмене специальных значений Отмена специального значения следующей литеры. Отмена специального значения группы литер, за исключением самой литеры '. Отмена специального значения группы литер, за исключением литер $ ' \ ". Зарезервированные слова if then else elif fi case in esac for while until do done {}
ПРИЛОЖЕНИЕ 7 ЗАПРОСЫ ФОРМАТОРА troff Сводка запросов В приводимой ниже сводке запросов используются следующие обозначения: F М N R Название шрифта (см. запрос .ft). Числовое выражение. Числовое выражение. Имя регистра, состоящее из одной или двух .ad с литер. Выравнивать выходные строки; с — режим выравнивания. .af R с Задать формат для регистра R (с=1, i, I, а, А). .ат хх у у .as хх цепочка Записать в конец макроопределения хх. Приписать заданную цепочку к цепочке с именем хх. .bd F N Шрифт F, утолщенный на N—1 базисных единиц. •bd S F N Использовать специальный утолщенный шрифт всегда, когда текущим является .bp шрифт F. Завершить текущую страницу; номер сле- дующей страницы равен Af. •br .c2 c Перейти на новую строку. Использовать в качестве управляющей ли- теры, блокирующей переход на новую строку, литеру с (обычно ')• .cc c Использовать в качестве основной управ- •ce V ляющей литеры литеру с (обычно .). Сцентрировать Af следующих входных строк текста. .ch xx N Изменить положение ловушки.
422 Приложение 7. Запросы форматора troff .cs FNM Отводить под каждую литеру поле постоян- ной ширины (для шрифта F). .cu N Подчеркивание непрерывной чертой в nroff. Аналогичен запросу ul в troff. .da xx Накапливать вывод, записывая его в конец макро хх. .de xx yy Определить или переопределить макро хх\ определение заканчивается макровызовом УУ- .di xx Накапливать вывод в макро хх. .ds xx цепочка Определить цепочку (регистр) хх, содержа- щую заданную цепочку. .dt N xx Установить ловушку в накопителе. .ec c Использовать в качестве авторегистра ли- теру с. .el любые-данные Часть else условного запроса if-else. .em xx По концу входного текста вызвать макро XX. .eo Отключить механизм авторегистра. .ev N Переключиться на среду выполнения N (уп- рятывание). .ex Выйти из nroff/troff. .fc a b Использовать в качестве разделителя по- лей литеру а, а в качестве заполнителя полей — литеру Ь. .fi Установить режим заполнения выходных строк. .fl Вытолкнуть содержимое из буфера вывода. .fp W F Шрифт F имеет физический номер 1^АТ^4. .ft F Сделать текущим шрифт F — х, хх или 1—4. Имеются также функции \fx, \f(xr, \fAC .he c Сделать индикатором переноса литеру с. .hw слово! . . . Слова-исключения из общих правил пере- носа. .h у N Установить режим переноса; N — номер режима. .ie с любые-данные Часть if условного запроса if-else; имеет те же формы, что и запрос if. .if N любые-данные Взять любые-данные, если значение выра- жения N больше 0. .if 'текст!'текст2' любые-данные Взять любые-данные, если цепочки текст1 и текст2 совпадают.
Приложение 7. Запросы форматора troff 423 .if с любые-данные Взять любые-данные. если условие с ис- тинно. В случае нескольких строк исполь- зуется конструкция \{любые-данные\\. .if ! W любые-данные Взять любые-данные. если выражение Л^О. .if \'текст!'текст?' любые-данные Взять любые-данные. если цепочки текст] и текст? не совпадают. if !с любые-данные Взять любые-данные. если условие с ложно. •ig УУ Игнорировать последующий входной текст вплоть до макровызова уу. .in Сдвиг края. .it N хх Установить ловушку по количеству вход- ных строк. .1с с Установить литеру заполнения для начала заголовка. • 1g N Установить режим с лигатурами, если N>0. .11 ±У Задать длину выходной строки. .Is М После каждой выходной строки вставлять N—1 пустую строку. .it ±JV Длина заголовка. .me с N Печатать литеру с справа от каждой выход- ной строки на расстоянии W эм от правой границы текста. .mk R Запомнить в регистре R текущую верти- кальную позицию. ,na Установить режим без выравнивания вы- ходных строк. .ne N Зарезервировать место под строк в пре- делах одной страницы. .nf Установить режим без заполнения и вырав- нивания выходных строк. .nh Запрет переноса слов. ,nm MSI Установить или отменить нумерацию строк; установка параметров нумерации. .nn N Отменить нумерацию для N следующих выходных строк текста. .nr R ±W M Определить числовой регистр R и присво- ить ему значение N; М — величина авто- матического приращения. .ns Запретить пропуск строк при печати (по- давление запросов .sp). •nx имя-файла Перейти к обработке следующего файла.
424 Приложение 7. Запросы форматора troff .os Отвести место под ранее зарезервирован- ный блок. .рс с Задание литеры для порождения номеров •pi программа страниц (обычно %). Направить выходной текст через транспор- тер в указанную программу (только для nroff). •pl .pm t Установить длину страницы. Распечатать имена и размеры макроопреде- лений. Если задано t. выводится только .pn ±W .po ±N общий суммарный размер. Номер следующей страницы N. Смещение относительно левого края физиче- ской страницы. .ps ±W Задание размера литер. Имеется также .rd приглашение функция \s±W. Считать вставку из файла стандартного ввода. .rm xx Исключить запрос, макроопределение или цепочку с именем хх. .rn хх у у Переименовать запрос, макроопределение или цепочку хх в уу. .rr R .rs Исключить (числовой) регистр R. Разрешить пропуск пустых строк при пе- чати (отмена режима .ns). .rt ±W Вернуться (только вверх) на сохраненную вертикальную позицию. .so имя-файла Переключиться на указанный исходный .sp /V файл с последующим возвратом назад. Сдвиг на N строк по вертикали вверх или вниз. .ss N Установить размер пробела равным Л7/36 .sv N .ta Nt.... ЭМ Зарезервировать блок из N пустых строк. Установка позиций табуляции. Если /=R, поле выравнивается по правому краю, если /=С — центрируется. Если t опущено, по- •tc c ле выравнивается по левому краю. Задание литеры, используемой как запол- нитель полей при табуляции. .ti ±/V Отступ (только для одной строки). . tl 'левая-часть'середина'правая-часть' Колонтитул из трех частей.
Приложение 7. Запросы форматора troff 425 .tm цепочка Вывести заданную цепочку литер на тер- минал (в стандартный файл диагностики системы UNIX). .tr abed... При выводе преобразовывать литеры а в Ь, с в d и т. д. •uf F Использовать вместо подчеркивания шрифт F (переключение на этот шрифт осуществ- ляется по запросу ul). .ul У Подчеркнуть (вывести курсивом в troff) N следующих входных строк. .vs N Установить интервал между строками (V) равным N пунктам. .wh N xx Установить страничную ловушку на по- зицию N по вертикали. Если N отрицатель- но, отсчет ведется от нижнего края стра- ницы. Авторегистры, функции и литеры \е Литера \. Блокировка или задержка ин- терпретации литеры \. Вывод текущего авторегистра в графичес- ком виде. Литера эквивалентно \(аа. Литера эквивалентно \(ga. Знак — (минус) в текущем шрифте. \ (пробел) Точка. Используется во вложенных макро (см. de). Явный, «нетривиальный» пробел. Его ширина равна ширине обычного про- бела. \о \1 Пробел шириной в цифру. «Узкий» пробел шириной 1/6 эм (шириной 0 в nroff). \Л Половина «узкого» пробела — пробел ши- риной 1/12 эм (шириной 0 в nroff). \& \1 Фиктивная литера с нулевой шириной. Индикатор строки, копируемой без изме- \$у нения в выходной текст. Начало комментария. Подстановка параметра макроопределения 1<У<9. \% Подразумеваемая литера предпочтитель- \(хх ного переноса. Литера с именем хх.
426 Приложение 7. Запросы форматора troff \*х, \*(хх Подстановка цепочки с именем х или хх. \а Неинтерпретируемая раккордовая литера. \b'abc...' Функция построения произвольных ско- бок любого размера. Разбиение входной строки. Следующая входная строка рассматривается как про- должение данной. \d Сдвиг по вертикали вниз или вверх на 1/2 эм (на 1/2 строки в nroff). \fx, \f(xr, \fjV Сделать текущим шрифт с именем х или хх или с физическим номером N. \h'N' Локальный сдвиг по горизонтали: вправо, если N положительно, и влево, если N от- трицательно. \кх Запомнить в регистре х текущую позицию по горизонтали данной входнЬй строки. \I'W Функция, рисующая горизонтальные ли- нии (из литер с, если с задана). \L'W Функция, рисующая вертикальные линии (из литер с, если с задана). Подстановка числового регистра х или хх. \nx,\n)xx \o’abc...' Наложить друг на друга литеры а, Ь, с, \P Принудительное завершение выходной стро- ки с выравниванием ее по правому краю. \r Сдвиг на 1 эм вверх (сдвиг на 1 строку вверх в nroff). \s/V, \s±W Функция изменения размера литер. \t Неинтерпретируемая литера горизонталь- ной табуляции. \U Сдвиг вверх на 1/2 эм (на 1/2 строки в nroff). \v'AT Локальный сдвиг по вертикали в пределах одной строки. Сдвиг на N вниз, если N положительно, и вверх, если N отрицатель- но. \w'цепочка' Подстановка длины указанной цепочки ли- тер. \x'N’ Функция отведения дополнительного места под выходную строку (при отрицательном N отводится место выше строки, а при по- ложительном — ниже строки). \zc Напечатать литеру с с «нулевой шириной» (следующая литера будет печататься на том же месте). \{ Начало блока в условном запросе.
Приложение 7. Запросы форматора troff 427 \} Конец блока в условном запросе. \(новая-строка) Игнорирование литеры новой строки. \Х X, любая литера, отличная от перечислен- ных выше. Предопределенные числовые регистры, доступные для чтения и записи % ct dl Номер текущей страницы. Тип литер (устанавливается функцией \w). (Максимальная) ширина текста, помещен- ного в накопитель (для последней завер- шившейся операции накопления). dn Высота (размер по вертикали) текста, по- мещенного в накопитель (для последней завершившейся”операции накопления). dw dy hp Текущий день недели (1—7). Текущий день месяца (1—31). Текущая позиция входной строки по гори- зонтали. In mo nl Номер выходной строки. Текущий месяц (1—12). Вертикальная позиция опорной линии для последней выведенной строки. sb Величина, на которую выступает ниже опорной линии данная цепочка литер (ус- танавливается функцией \w). st Величина, на которую выступает выше опорной линии данная цепочка литер (ус- танавливается функцией \w). yr Две последние цифры текущего года. Предопределенные числовые регистры, доступные только для чтения .А Количество параметров в текущем макро. В nroff всегда равно 1; в troff устанавли- вается равным 1, если задана опция —а. .Н Доступное разрешение по горизонтали (в базисных единицах). .Т В troff всегда равно 0; в nroff устанавли- вается равным 1, если задана опция —Т. .V Доступное разрешение по вертикали (в ба- зисных единицах). .а Размер дополнительного пространства, от- веденного ниже строки с помощью функций \х'Л/'.
428 Приложение 7. Запросы форматора troff .С Количество входных строк, считанных из .d текущего входного файла. Текущая позиция по вертикали в текущем накопителе; совпадает со значением регист- ра nl вне накопителя. Л .h Тип текущего шрифта (1—4). Наибольшая возможная позиция (по вер- тикали) строки на текущей странице или в текущем накопителе. л .1 .и Текущий сдвиг края. Текущая длина выходной строки. Длина текста в последней выведенной строке. .0 Текущее смещение относительно левого края физической страницы. •р .S Л • U Текущая длина страницы. Текущий размер литер (в пунктах). Расстояние до следующей ловушки. Равно 1 в режиме с заполнением строк и 0 в режиме без заполнения строк. .V .W .X Текущий интервал между строками. Ширина предыдущей литеры. Зарезервированный регистр; его смысл за- висит от версии. •У Зарезервированный регистр; его смысл за- висит от версии. •Z Имя текущего накопителя.
Приложение 7. Запросы форматора troff 429 Специальные литеры 1 • V \(*n \(ap < я f \Cc * \(!- — \(em 0 \(*o \(-> • — 7Г \Cp \«- • \(hy P \(*r 1 \(ua — \- c \(*s 1 \(da • \(bu s \(ts X \(mu □ \(sq T \(*t 4- \(di \(ru V \(*u ± \(+- »/♦ \(14 Ф \(*f 1 J \(cu «/2 \(12 X \(*x 1 n \(ca 3/4 \(34 Ф \(*q I c \(sb fi \(fi w \(*w \(sp fl \(fl A \(*A 1 c \(ib fT \(ff В \(*B 2 \(ip ffi \(Fi Г \(*G < X) \(if ffl \(F1 Д \(*D d \(pd • \(de E \(*E 1 7 \(gr t \(dg Z \(*Z \(no 1 \(fm H \(*Y J \(is Ф \(ct 0 \(*H ОС \(pt \(rg I \(*I i \(es © \(co К \(*K < \(mo + \(pl A \(*L 1 \(br — \(mi M . \(*M 4 \(dd ж \(eq N \(*N \(rh « \(** a \(*C * \(lh § \(sc 0 \(*O ( \(bs \(aa П \(*P 1 \(or 4 \(ga p \(*R ( D \(ci \(ul 2 \(*S \(lt 7 \(sl T \(*T \(lb a \(*a Y \(*U \(rt fi \(*b Ф \(*F \(rb У \(*g X \(*X \(lk d \(»d ¥ \(*Q \(rk € \Ce n \(*W \(bv \(*z r/ \(sr \(lf V \(*y \(rn \(rf 0 \(*h \3> \(>- \(lc I \(*i \«- \(rc ft \(*k a- = \(— X \(’l Sx \C- \(*m
ПРИЛОЖЕНИЕ 8 КОМАНДЫ РЕДАКТОРА vi Простейшие команды AD Продвинуть окно вперед. ли Продвинуть окно назад. AF Продвинуться вперед на страницу. лв Продвинуться назад на страницу. возврат каретки Переместить курсор вниз. — Переместить курсор вверх. пробел Сдвинуть курсор вправо. возврат на шаг Сдвинуть курсор влево. dd Исключить текущую строку. i Вставить текст перед текущей литерой. , 0 Вставить текст вслед за текущей строкой. Р Вставить исключенный или скопированный текст. X Исключить текущую литеру. Y Скопировать группу, строк в скрытый буфер. :w file Записать отредактированный текст в файл file. :q Выход из редактора. Команда :q! осуществляет выход, не проверяя, сохранен ли редактиро- ванный текст. del Прервать выполнение текущего запроса. Управление курсором и экраном H Установить курсор на первую строку экрана. L Установить курсор на последнюю строку экрана. M Установить курсор на середину экрана. hjkl Сдвинуть курсор влево, вниз, вверх или вправо соответственно. wbe Установить курсор на следующее слово, на пре- дыдущее слово или на конец текущего слова.
Приложение 8. Команды редактора vi 431 /.../ Поиск по образцу ... в прямом направлении. ?...? Поиск по образцу ... в обратном направлении, z. Продвинуть экран так, чтобы текущая строка оказалась в его середине. z ВК Продвинуть экран так, чтобы текущая строка стала первой строкой экрана. В К означает воз- врат каретки. zn. Использовать окно из п строк. Окно размеща- ется в центре экрана. % Установить курсор на следующую или предыду- щую парную скобку (, ), { или }. ЛЕ Продвинуть экран на одну строку вперед. AL Восстановить изображение на экране. AY Продвинуть экран на одну строку назад. О Установить курсор в начало строки. Запросы редактирования А... Вставить текст в конец текущей строки (встав- ляемый текст оканчивается авторегистром esc). С... Заменить остаток строки (заменяющий текст оканчивается авторегистром esc). D I... Исключить остаток строки. Вставить текст в начало текущей строки (встав- ляемый текст оканчивается авторегистром esc). J X CW... Объединить текущую и следующую строки. Удалить литеру перед курсором. Заменить текущее слово (заменяющий текст оканчивается авторегистром esc). гх Заменить текущую литеру на литеру х. Изменить регистр текущей литеры. Прописная буква заменяется строчной, строчная — пропис- ной. & Повторить последний запрос замены :s. Использование запросов редактора ed В редакторе vi можно использовать запросы редактора ed, пред- варяя их двоеточием. :sh Вызвать программу-оболочку. :!cmd Выполнить команду cmd и вернуться в vi. :r file Считать файл file. :s... Заменить одну цепочку литер на другую. :g... Глобальный поиск по цепочке.
432 Приложение 8. Команды редактора vl Объекты Объекты специфицируются следующим образом: с Одна литера. w Буквенно-цифровое слово. W Следующее слово, составленное из литер, отлич- ных от пробела и табуляции. Н Первая строка экрана; ЗН означает третью сверху строку экрана. L Последняя строка экрана. 3L означает третью сни- зу строку экрана. /.../ Следующая строка, содержащая образец ... . ) Конец текущего предложения. Предложение за- канчивается пустой строкой или одной из литер .,!,?, за которой следует новая строка или два пробела. ( Начало текущего предложения. } Конец текущего абзаца. Абзац заканчивается пус- той строкой или одним из запросов форматора nroff: .bp, .IP, .LP, .PP, .QP, .LI, .P. { Начало текущего абзаца. ]] Конец текущего раздела. Раздел заканчивается одной из макрокоманд. N Н,. SH,. Н U ил и . Н форма- тора nroff. [I Начало текущего раздела. Эти объекты используются как параметры в следующих командах: сх... Заменить текст вплоть до х включительно новым текстом, заканчивающимся авторегистром esc. dx Исключить текст вплоть до х включительно. ух Скопировать объект х для последующего использо- вания в команде р или Р. Сделать отступ из 8 пробелов во всех строках вплоть до строки, содержащей х, включительно. <х Устранить отступ из 8 пробелов во всех строках вплоть до строки, содержащей х, включительно. !х cmd Заданный объект х передается команде cmd в ка- честве стандартного ввода. Команда выполняется, и объект замещается ее стандартным выводом. Коэффициенты Число, предшествующее команде, является коэффициентом крат- ности выполнения команды, за исключением следующих случаев: новый размер окна [[]]:/? величина, на которую продвигается окно AD AU номер строки или столбца z G |
Приложение 8, Команды, редактора vi 433 Установка внутренних переменных Каждая внутренняя переменная имеет имя и устанавливается одной из команд :set имя-переменной :set имя-переменной—значение^ Соответствующий режим отменяется командой :set по имя-переменной Ниже приводится список имен внутренних переменных. В скоб- ках даются допустимые сокращения. autoindent(ai) Делать автоматические отступы в тексте про- грамм. autowrite(aw) Автоматическая запись буфера в файл перед выполнением запросов :п и !. ignorecase(ic) При выполнении поиска не различать про- писные и строчные буквы. list ' number(nu) Выдавать литеры табуляции в виде Л1. Выдавать строки текста вместе с их номерами. paragraphs(para) Список имен макрокоманд форматора nroff, redraw(re) задающих начало абзаца (для запросов } и {). Начальное значение — IPLPPPQPbpP LI. Моделирование интеллектуального термина- пя sections(sect) vid. Список имен макрокоманд, задающих начало раздела (для запросов [[ и ]]). Начальное значение—NHSHH HU. term Имя типа используемого терминала. 15 с. Баурн
ПРИЛОЖЕНИЕ 9 МАКРОБИБЛИОТЕКА ,. V Макробиблиотека , описанная в гл.7. ,, \" Первые несколько запросов устанавливают регистры . д \” и ловушки для общего использования. Следующие. , w \н далее запросы сгруппированы по выполняемым V функциям ; они описаны в разд.7.1.4. У—•—------------------------------------------— .. V подразумеваемые лигатуры JqO У печать через 2 интервала для nroff ( при отладке ) .if n .Is 2 < .. У установка интервала между строками t принятого в . ps 10 у издательстве .vs 12р .. У длина строки и длина заголовка .II 4.651 .It4.65i .. У регистр re • текущий сдвиг края . nr га О .in \n(ra • * У регистр pd - промежуток между абзацами . if n . nr pd 1 .if t .nr pd .4 .. V регистр hl - полинтервала .if n .nr hl 1v .if t .nr hl .5v •. У регистр sd • флаг для задания интервала перед заголовками . nr sd 1 V регистр ip • величина сдвига края для абзацев .nr ip 2 .. У регистр fn • нумерация рисунков .nr fn 0 1 • . У установка ловушек в начале и в конце страницы у--------------------------------- ... , У ловушка в начале страницы .wh О аа . У ловушка в конце страницы .lfn.wh-5zz .If t .wh 9i zz
Приложение 9. Макробиблиотека 435 .. V начало страницы .deaa ,ev 1 Jt7i . tl'—"—* . II 4.6Si .It 4.65I sp 5 • ps 8 • ft R .if e .tl 4\h’2m'The UNIX System"\V(sh’ .If о .tl '\\*(sh"\\*(ct\h'2m'%' .ev 'sp .mk .. \" конец страницы .de zz 'sp • tl "\\»(pn" \\.ds pn 'bp .". \* установка конца файла . em ее • • V обработка конца файла . (Гв ее . af % 1 .tm LAST\\n% .. \" вывод в две колонки для предметного указателя . de 2с .ie \\n(sw \( . nr SW О .in О .bp .ns \) • el \{ . nr SW 1 .rt .in 13i \} .. \N Запросы, предоставляемые пользователям библиотеки v----------——-----------------------~ .de СН \* заголовок главы .CH 1 "Введение" .)Н "Chapter \\$ГЛ\$а* W.ds sh \\$1 15ф
436 Приложение 9. Макробиблиотека .de АН \” заголовок приложения.АН 1 "Команды" • }н "Appendix \\$1" Л\$2" . de }Н \" внутренние макро для заголовков глав и приложений . sp 7 \\.ds cf\\$1 \\.ds ct \\$2 \\. ds pn \\n% .ft H .ps 24 . sp 24p .ce 2 \\$1 .sp 2 \\$2 .sp 4 .ps .mk .de SH V заголовок раздела .SH 1.1 "Историческая справка" . if n . sp 2 \\.dssh\\$1 .if t .sp 15p . ne 2 .ps +2 .ft HB . in \\n(rs \\$1\\\\\\$2 .ps -2 .ft R .if n .sp . if t . sp 6p .NS . de SS \" заголовок подраздела . SS 6.2.1 "Имена команд" . sp \\n(sd \\.dssh\\$1 .ne 3 .ftHB . in \\n(rs \\$1\\\\\\$2 .ft R .sp 3p .NS •• de MS V подзаголовок . MSиИспользование литеры обратная косая черта • 8р\\п($СГ
Приложение 9. Макробиблиотека 437 .пе 2 .ft HI . in \\n(rs \\$1 .ft R . sp 3p .NS . de NS V отмена пропуска строки после заголовка . it 1 on V пропустить строку t если нет другого заголовка . nr sd О • de on .nr sd 1 . de LP \” начало абзаца без отступа . LP . sp \\n(pd . in \\n(rs ; .ta 2m . de PP \ \H начало абзаца с отступом в первой строке . РР .LP • ti +2щ V' .IP "(а)" 12 . de IP \я сдвинутый абзац с висячим текстом слева .MPA\fR\\$l\\fP»*\\$2* .deBU '♦ \" сдвинутый абзац, помеченный жирной точкой .BU .MP ”\\fR\(bu\\fP" "4” .. \и .MP "main»" 12 . de MP Vсдвинутый абзац с висячим фрагментом программы . sp \\n(pd . ie \\$2 . nr xi \\$2-\\n(ip .el .nr xi 4 . in \\n(rs+\\n(xi+\\n(ip . ta \\n(xi . ti -\\n(xi .ft H \&\\$l\t\c \. if \\*А\$ i 'u-\\n(xim . br .ft R .. 4 .de XV ,nrhl+.1v \deVX .nr hl iv
438 Приложение 9. Макробиблиотека de HL \* сдвиг вниз на полинтервала . HL . sp \\n(hlu .. \" Иллюстрации и тексты программ V------------—— -------------——1 . de DS \” начало иллюстрации .DS 'in +2m 'ta 4m 8m 12m 16m 20m 24m 28m 32m .HL 'nf 'ne\\$t .de DE \N конец иллюстрации .DE .HL .fi .in -2m .ft R .de TS \и начало таблицы .TS .HL .DS . de ТЕ \" конец таблицы .ТЕ • DE .HL .de EX \” начало примера .EX 24 ... H 7 .fl .ss 20 'DS \\$1 • de ХЕ V конец примера «ХЕ .DE .ss 12 .ft R . de RS \и начало сдвинутого участка текста , RS .nr rs +2 . de RE V конец сдвинутого участка текста а R6 .nr rs -2 .de RU \” горизонтальная черта *RU . .br \l'4.65i-4r
.de FX' V начало рисунка в тексте .FX 24 ’EX\\$f 'RU .deXF> V конец рисунка в тексте .XF 'RU .ХЕ • * . de FG \" включение файла, содержащего рисунок . FG lock. с 13 • FX\\$2 .so .XF .de FC V ПОДПИСЬ К рисунку .FC ^.3’’Создание файла* замка” .ft в .се Figure \\$1\\\\$2 .ft R .sp • NS . de CM \* текст команды . CN "Is" \&\fH\\$1\fR .de ON V определение в тексте .DN "полномочий” \&\fl\\$1\(R . de SN V имя символа (литеры) в тексте . SN "NEWLINE" \&\fH\\$t\fR . de HI V шрифт для заголовков подразделов . HI "заголовок” \&\f(HI\\$1\fP . de IX \* элемент предметного указателя . tm \\$ 1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\п% . de СХ V парные элементы предметного указателя .IX'W.’W .1Х"\\$2,Я W* .. V Определения цепочек V—-------------- .if \n(mo-O .da МО January .if \n(mo-1 .ds MO February .if \n(mo~2 .ds MO March .if \n(mo-3 .ds MO April .if \n(mo-4 .ds MO May .it \n(mo-5 .ds MO June
440 Приложение 9. Макробиблиотека if \n(mo-o .ds MO July if \n(mo-7 .ds MO August if \n(mo-8 .ds MO September if \n(mo-9 .ds MO October if \n(mo-.10 .ds MO November if \n(mo—11 ds MO December \" D . , ds O\&. • \" DD .. .ds DD ,\l. VZZ ... .ds ZZ\& \l,\|, \"ST • .ds ST \s+l\(*’\s-1 V vt I • ds VT \l\(or\l \" AP » .ds AP >\h'-,2m'> \" HE « .ds HE <\h'-.2m'< \"TW ~ ds TW \v*.6m'\s+4~\s0\v,r-.6m* ’ V CT a .ds CT \v'.6m'\s+4AsO\v'- .6m* V AT @ .ds AT \v'~.2m'@\v'.2m* V T T в кружочке обозначает у» табуляцию ds T \I\h'. 5n \v'~.2n’\s7\zT\sO\s 12\v'. 2n*\h'-. 5nA(ci\I \sO \" нижние индексы ds О \v*. 25m’\s—40\s0\y'~. 25m* ds 1 \v*.25m'\s-4l\sO\v'-.25m* ds 2 \v'.25m‘\s-42\sO\v'—. 25m' ds 3 \v*. 25m'\s—43\s0\v'—. 25m* ds n \v'.25m'\s-4n\sO\v'-.25m*
ПРИЛОЖЕНИЕ 10 БИБЛИОТЕКА МАКРООПРЕДЕЛЕНИЙ ms Описываемый пакет макроопределений для nroff и troff обес- печивает возможность форматирования технических документов в различных форматах. Для вывода текста на терминал в две колонки его следует пропустить через фильтр col(l). Макрозапросы библиотеки ms приводятся ниже. Многие из запросов систем nroff и troff при совместном использовании с дан- ным пакетом могут вызвать нарушения в функционировании последнего. Однако следующие запросы можно безбоязненно употреблять после первого макровызова .РР: .Ьр Начать новую страницу. .nf Установка режима без заполнения и выравнивания выходных строк. .Ьг Перейти на новую строку с данного места. .sp п Вставить п пустых строк. .Is п Расстояние между строками: п = 1 — вывод через один интервал, п=2 — вывод через два интервала. .па Отмена выравнивания по правому краю. В качестве ввода для nroff и troff может использоваться вывод препроцессоров eqn, neqn, refer и tbl(l), предназначенных для подготовки математических формул и таблиц. Список запросов Запрос Началь- Вызы- ное зна- вает пе- .1С чение реход на но- вую строку да да Пояснение Вывод в одну колонку, начиная с новой страницы.
442 Приложение 10. Библиотека макроопределений ms .2С нет да Вывод в две колонки. .АВ нет да Начало аннотации. ,АЕ — да Конец аннотации. .AI нет да Далее следует название учреж- дения, где работает автор. В фор- мате ТМ игнорируется. .АТ нет да Печатает «Attached» («Прило- жение:») и выключает режим за- полнения строк. .AU х у нет да Далее следует фамилия автора. Параметр х указывает место жи- тельства и дополнительную ин- формацию; игнорируется во всех форматах, кроме ТМ. .В х нет нет Напечатать х полужирным шрифтом. Если параметров нет, печатать последующий текст по- лужирным шрифтом. .В1 нет да Начало текста, который будет помещен в рамку. .В2 нет да Конец текста, помещаемого в рамку, и его печать. .ВТ дата нет Колонтитул внизу страницы. Это макро вызывается автомати- чески при достижении конца страницы. Его можно переопре- делить. ,ВХ х нет нет Напечатать текст х в рамке. .CS х... да Задание итоговой информации о документе. Игнорируется во всех форматах, кроме ТМ. Па- раметрами являются число стра- ниц текста, число прочих стра- ниц, общее количество страниц, число рисунков, таблиц, ссы- лок. .СТ нет да Напечатать «Copies to» («Копии в») и установить режим без за- полнения строк. .DA х nroff нет В качестве текста, содержащего дату и помещаемого в нижней части страницы, использовать х. Подразумеваемым значением яв- ляется текущая дата.
Приложение 10. Библиотека макроопределений ms 443 .DE — •DS х нет .EG нет .EN — .EQ x у — .FE — •FS нет .НО — .1 x нет да Конец иллюстрации. Влечет .КЕ. да Начало иллюстрации. Последу- ющие строки копируются в вы- ходной текст без изменений. Ес- ли х=1 (подразумеваемое зна- чение), все строки иллюстрации выводятся с отступом; если x=L — выравниваются по лево- му краю страницы; если х=С ' — центрируются; если х=В, то. сначала весь блок выравнива- ется по левому краю, а потом центрируется как единое целое. Влечет .KS. — Печать документа в формате, используемом в фирме Bell La- boratories для технической до- кументации. Этот запрос должен стоять первым. да Интервал после печати уравне- ния; уравнение обрабатывается препроцессором eqn или neqn. да Этот запрос ставится перед урав- нением. Текущая строка завер- шается, и делается интервал. Параметр у задает номер урав- нения. Необязательный пара- метр х может принимать значе- ния I (подразумеваемое) — вы- вод уравнения с отступом, L — выравнивание по левому краю или С — центрирование урав- нения. да Конец подстрочного примечания, нет Начало подстрочного примеча- ния. Это примечание будет по- мещено в нижней части стра- ницы. нет «Bell Laboratories, Holmdel, New Jersey 07733» («Фирма Bell Laboratories, Холмдел, Нью- Джерси 07733»). нет Вывести текст х курсивом. Если х опущен, курсивом вы- водится последующий текст.
444 П риложе.ние 10. Библиотека макроопределений ms лн нет нет «Bell Laboratories, Naperville, лм нет нет Illinois 60540» («Фирма Bell La- boratories, Нейпирвиль, Илли- нойс 60540»). Печать в формате, используе- ЛР X у нет да мом в фирме Bell Laboratories для служебных записей. Этот запрос должен стоять первым. Начало сдвинутого абзаца с ви- ЖЕ да сячей меткой х слева. Величина сдвига — у эн (по умолчанию — 5). Конец накопления. Если для ЖЕ нет да накопленного текста не хватает места на текущей странице, он помещается на следующую стра- ницу. Начать накопление «плаваю- .KS нет да щего» текста. Если накоплен- ный текст придется перенести на следующую страницу, после- дующий текст будет продолжен на текущей странице. Начать накопление последую- .LG нет нет щего текста. Увеличить размер букв. .LP да да Начать абзац без отступа в пер- .MF — — вой строке. Печать в формате, используемом .МН нет в фирме Bell Laboratories для архивных документов. Этот за- прос должен стоять первым. «Bell Laboratories, Murray Hill, .MR New Jersey 07974» («Фирма Bell Laboratories, Марри Хилл, Нью- Джерси 07974»). Печать в формате, используе- .ND дата troff нет мом в фирме Bell Laboratories для отчетных документов. Этот запрос должен стоять первым. Использовать дату (если она задана) только в специальных местах, определяемых формата- ми фирмы Bell Laboratories. Не указывать дату в нижней части страницы.
Приложение 10. Библиотека макроопределений ms 445 .NH п —— да Этот запрос аналогичен .SH, но номера разделов генерируются автоматически. Разделы имеют многоуровневую нумерацию ви- да 1.2.3; п указывает желаемый уровень (подразумевается 1). .NL да нет Установить стандартный размер букв. .OK — да Далее следуют «прочие ключевые слова» для титульного листа записей в формате ТМ. PP нет да Начало абзаца. В первой строке абзаца делается отступ. .PT № стр. Колонтитул. Это макро вызы- вается автоматически в начале каждой страницы. Его можно переопределить. .PY нет «Bell Laboratories, Piscataway, New Jersey 08854» («Фирма Bell Laboratories, Пискатауэй, Нью- Джерси 08854»). •QE — да Конец выделенного (с отступами слева и справа) участка текста. •QP — да Начало одиночного выделенного абзаца (с отступами слева и справа). •QS — да Начало выделенного (с отсту- пами слева и справа) участка текста. •R да нет Следующий далее текст выво- дится прямым светлым шрифтом. .RE — да Конец участка с отступом. •RP нет - Титульный лист и первая стра- ница для статьи, подготовлен- ной к публикации. Этот запрос должен предшествовать всем остальным. .RS да Начало участка с отступом. В последующих запросах .IP от- ступ измеряется от текущей гра- ницы. .SG x нет да Вставить подпись (подписи) ав- тора (авторов). Игнорируется во всех форматах, кроме ТМ. Пара- метр х задает фамилии автора и машинистки.
446 Приложение 10. Библиотека макроопределений ms .SH — да Далее следует заголовок раз- дела, автоматически набирае- мый полужирным шрифтом. .SM нет нет Уменьшить размер букв. .ТА х... 5... нет Установка позиций табуляции. По умолчанию — 5 10 15 . . . (единица измерения — эн). .ТЕ — да Конец таблицы. .TH — да Конец заголовков таблицы. .TL нет да Далее следует заголовок. .TM x... нет Печать документа в используе- мом в фирме Bell Laboratories формате ТМ. Параметрами яв- ляются номер ТМ, номер ва- рианта (номера вариантов, за- ключенные в кавычки), регист- рационный номер. Этот запрос должен предшествовать другим запросам. .TR x Печать в формате, используемом в фирме Bell Laboratories для технических отчетов. Номер от- чета — х. Этот запрос должен стоять первым. .TS x да Начало таблицы. Если х равно Н, таблица имеет повторяющий- ся заголовок. .UL x — нет Подчеркнуть (даже в troff) текст, заданный в качестве параметра. .UX нет «UNIX». При первом употребле- нии добавляется подстрочное примечание «UNIX is a trade- mark of Bell Laboratories» («UNIX — торговая марка фир- мы Bell Laboratories»). .WH нет «Bell Laboratories, Whippany, New Jersey 07981» («Фирма Bell Laboratories, Уиппени, Нью- Джерси 07981»).
ПРИЛОЖЕНИЕ 11 НАБОР ЛИТЕР ASCII Восьмеричные значения ООО nul 001 soh 002 stx 003 etx 004 eot 005 enq 006 ack 007 bel 010 bs Oil ht 012 nl 013 vt 014 np 015 cr 016 so 017 si 020 die 021 del 022 dc2 023 dc3 024 dc4 025 nak 026 syn 027 etb 030 can 031 em 032 sub 033 esc 034 fs 035 gs 036 rs 037 us 040 sp 041 ’ 042 " 043 # 044 $ 045 % 046 & 047 ' 050 ( 051) 052 » 053 + 054 , 055 - 056 . 057 / 060 0 061 1 062 2 063 3 , 064 4 065 5 066 6 067 7 070 8 0719 072 : 073 ; 074 < 075 - 076 > 077 ? 100 @ 101 A 102 В 103 C 104 D 105 E 106 F 107 G 110 H 1111 112 J из К 114L 115 M 116N 117 0 120 P 121 Q 122 R 123 S 124 T 125 U 126 V 127 W 130 X 131 Y 132 Z 133 Г ’ 134 135] 136 a 137_ 140 141 a 142 b 143 c 144 d 145 e 146 f 147 g 150 h 151 i 152 j 153 k 1541 155 m 156n 157o 160 p 161 q 162 r 163 s 164 t 165 u 166 У 167 w 170 x 171 у 172 z . 173 { 174 1 175) 176 - 177 del шестнадцатеричные значения 00 nul 01 soh 02 stx 03 etx 04 eot 05 enq 06 ack 07 bel 08 bs • 09 ht Oa nl Ob vt Oc np Od cr Oe so Of si 10 die 11 del 12dc2 13dc3 14 dc4 15 nak 16 syn 17 etb 18 can 19 em la sub lb esc 1c fs Id gs le rs If us 20 sp 21! 22" 23# 24$ 25% 26 & 27 ' 28 ( 29) 2а» 2b 4- 2c, 2d- ,2e. Iff 30 0 31 1 32 2 33 3 34 4 35 5 36 6 37 7 38 8 39 9 За: 3b; 3c < 3d- 3e > 3f ? 40 @ 41 A 42 В 43 C 44 D 45 E 46 F 47 G 48 H 491 4a J 4b К 4c L 4dM 4e N 4fO 50 P 51 Q 52 R 53 S 54 T 55 U 56 V 57 W •3X 59 Y 5a Z 5b [ 5c 5dl 5e a 5f_ 60 61 a 62 b 63 c 64 d 65 e 66 f 67 g 68 h 69 i 6a j 6b к 6c I 6d m 6e n 6f 0 70 p 71 q 72 г 73 s 74 t 75 u 76 v 77 w 78 x 79 у 7a z 7b ( 7c 1 7d) 7e * 7f del
ЛИТЕРАТУРА Ахо, Ульман (Aho А. V., Ullman J.D.) [1977] Principles of Computer Design. Addison Wesley: Reading, Mass. Баурн (Bourne S. R.) [1978] «UNIX Time-Sharing System: The UNIX Shell». Bell Sys. Tech. J. 57(6), 1971—1990. Бук (ред.) (Book R. V., ed.) [1980] Formal Language Theory. Perspective and Open Problems, 325— 344. Academic Press: New York. Дейтч, Лэмпсон (Deutsch L. P., Lampson B. W.) [1965] SDS„ 930 time-sharing system preliminary reference manual. Doc. 30.10.10, Project GENIE„. Univ. Cal. at Berkeley. [1967] «An online editor», Comm. Assoc. Comp. Mash. 10(12), 793—799, 803. Джонсон (Johnson S. C.) [1975] «Yacc — Yet Another Compiler — Compiler. Comp. Sci. Tech. Rep. No. 32». Bell Laboratories: Murray Hill, New Jersey. [1978] «Lint, a C Program Checker. Comp. Sci. Tech. Rep. No. 65». Bell Laboratories: Murray Hill, New Jersey. Джонсон, Ритчи (Johnson S. C., Ritchie D. M.) [1978] «UNIX Time-Sharing System: Portability of C Programs and the UNIX System». Bell Sys. Tech. J. 57(6), 2021—2048. Долота, Маши (Dolotta T. A., Mashey J. R.) [1976] «An Introduction to the Programmer’s Workbench». Proc. 2nd Int. Conf, on Software Engineering, 164—168. Долота, Хайт, Маши (Dolotta T. A., Haight R. C., Mashey J. R.) [1978] «UNIX Time-Sharing System: The Programmer's Workbench», Bell Sys. Tech. J. 57(6), 2177—2200. Керниган, Леек, Оссанна (Kernighan В. W., Lesk M. E., Ossanna J. F.) [1978] «UNIX Time-Sharing System: Document Preparation», Bell Sys. Tech. J. 57(6), 2115—2135. Керниган, Ритчи (Kernighan В. W., Ritchie D. M.) [1978] The C Programming Language. Prentice-Hall: Englewood Cliffs, New Jersey. [Имеется перевод: Керниган Б., Ритчи Д. Язык программирования Си.—М.: Финансы и статистика, 1985] Керниган, Черри (Kernighan В. W., Cherry L. L.) [1977] «А System for Typesetting Mathematics». Comm. Assoc. Comp. Mach. 18, 151—157. Крисмэн (ред.) (Crisman P. A. ed.) [1965] The Compartible Time-Sharing System. M. I. T. Press: Cambridge Mass. Леек (Lesk M. E.) [1975] «Lex—A Lexical Analyzer Generator. Comp. Sci. Tech. Rep« No. 39», Bell Laboratories: Murray Hill, New Jersey.
Литература 449 [1977] «Typing Documents on UNIX and GCOS: The—ms Macros for Troff», Bell Laboratories: Murray Hill, New Jersey. Ликлама (Lycklama H.) [1978] «UNIX Time-Sharing System: UNIX on a Microprocessor», Bell Sys. Tech. J. 57(6), 2087—2101. Макмахон, Черри, Моррис (McMahon L. E., Cherry L. L., Morris R.) [1978] «UNIX Time-Sharing System: Statistical Text Processing», Bell Sys. Tech. J. 57(6), 2137—2154. Оссанна (Ossanna J. F.) [1976] «NROFF/TROFF User’s Manual. Comp. Sci. Tech. Rep. No. 54». Bell Laboratories: Murray Hill. New Jersey. Ритчи (Ritchie D. M.) [1978] «UNIX Time-Sharing System: A Retrospective», Bell Sys. Tech. J. 57(6), 1947—1969. [1980] The Evolution of the UNIX Time-Sharing System. Language Design and Programming Methodology: Lecture Notes in Computer Science 79, 25—35, Springer-Verlag: New York. Ритчи, Джонсон, Леек, Керниган (Ritchie D. M., Johnson S. C., Lesk M. E., Kernighan B. W.) [1978] «UNIX Time-Sharing Svstem: The C Programming Language», Bell Sys. Tech. J. 57(6), 1991—2019. Ритчи, Томпсон (Ritchie D. M., Thompson K.) [1978] «The UNIX Time Sharing System», Bell Sys. Tech. J. 57(6), 1905— 1929. Ричардс (Richards M.) [1969] «BCPL: A Tool for Compiler Writing and Systems Programming», Proc. AFIPS SJCC, 34. Томпсон (Thompson K.) [1975] The UNIX Command Language. Structured Programming — Info- tech State of the Art Report 375—384. Nicholson House, Maidenhead, Berks- hire, England: Infotech International Ltd. [1978] «UNIX Time-Sharing System: UNIX Implementation», Bell Sys, Tech. J. 57(6), 1931—1946. Томпсон, Ритчи (Thompson К., Ritchie D. M.) [1975] UNIX Programmer’s Manual. Sixth Edition. Bell Laboratories: Mur- ray Hill, New Jersey. [1978] UNIX Programmer’s Manual. Seventh Edition. Bell Laboratories: Murray Hill, New Jersey. Фейертаг, Органик (Feiertag R. J., Organick E. I.) [1971] «The Multics input-output system», Proc. Third Symposium on Ope- rating Systems Principles, 35—41. Хартли (ред.) (Hartley D. F., ed.) [1968] The Cambridge Multiple Access System —Users Reference Manual» University Mathematical Laboratory: Cambridge, England.
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ Абзац 201, 223 — с висячим текстом 224 — сдвинутый 192, 223 Абзац, vi 67 Авторегистр (esc), vi 63 Авторегистровые последовательно- сти, С 113 Адресация строк, ed 48 Адресная арифметика, С 126 Адресное пространство (процесса) 180 Архив на ленте, tar 43 Атрибуты файла 72 Базисные типы данных, С 104, 112 Библиотека математических функ- ций math.h 108, 111, 145 — С-программ 145 — стандартных программ языка G 137 Блок, С 119, 134 Блочная структура, С 134 Буфер, ed 28 Буферизация ввода-вывода 137 Ввод-вывод 137, 176 Вектор параметров argv 155, 182, 184, 378 — сообщений sys_errlist 403 — среды arge 155 Верификатор программ lint 116, 144, 156, 324 Висячая метка, nroff 192 Включение файлов, G 133 Владелец файла 161, 162 Возврат из функции, С 111 Возврат каретки 17, 20 ----, С 113 ----, vi 62 Возврат на шаг 20 --------, С 113 --------, vi 62 Восстановление подразумеваемой реакции на сигнал 188 — текста, vi 64 — файла, ed 57 ----, vi 68 Восьмеричный дамп 42, 106, 333 Время выполнения программы 146 Вставка файла, ed 47 Встроенная функция, awk 250 --------exp 252 —-------index 252 -------- int 252 --------length 252 — '---log 252 --------sqrt 252 --------substr 252 Встроенный документ 76, 290 Вход в систему 17, 32 Входной файл 32, 79, 100 Вывод в несколько колонок 42 — оглавления 41 — последних строк файла 2б9 — строк в обратном порядке 259 ----через два интервала, nroff 194 Выделение памяти, G 129 Вызов макро, nroff 202 — форматора nroff 193 — функции, С 123
Предметный указатель 451 Выражение регулярное 246, 254, 257, 261, 319, 320 - С 114 — awk 249 Выход в оболочку, ed 58 — из редактора, ed 46 --------, vi 61, 63, 65 Вычисление команды, sh 91, Генератор отчетов awk 247 Глобальная замена, ed 53 Глобальный запрос, ed 56 — поиск, ed 57 Группа процессов 176 Группировка команд, sh 84 Дамп программы 148 Дата, nroff 209 Двойная кавычка, nroff 216 Действие, awk 247 Дескриптор файла 28, 158, 159 ---дублирование 98, 159 Длина колонтитула, nroff 201 — страницы, текущая, nroff 211 — строки, nroff 195 ---текущая, nroff 211 — цепочки 170 Документация по системе UNIX 21 ---стандартным библиотекам 145 Доступ к файлу 161 Журнал работ, uucp 259 --- печать 259 Завершение процесса 181 Зависание, ed 57 Заголовки глав, nroff 222 — разделов, nroff 220 Загрузчик 146 Закрытие файла 161 Замена литеры, vi 64 — слова, vi 66 Запись в файл, ed 46 --------, vi 63 Запрос 45 Запросы редактора ed 45, 416 -------- аннулирование 54 -------- вставка 46 --------выход 46 --------дозапись 46, 49 --------замена 52, 55 ----------- строк 49 -------- запись 46 --------исключение строк 47, 50 -------- маркировка 59 --------объединение строк 59 --------пересылка строк 47 --------чтение 47 --------d 47, 50 --------f 47 --------1 59 --------р 47, 48 --------t 48 --------v 57 --------//53 Запросы форматора nroff 194 -------- ad 196 --------af 204, 209 --------bp 200 --------br 196 -------- ce 195 --------de 201 --------di 217 --------ds 208 --------ev 216 —-------fi 196 --------ft 213 --------hw 197 -------- ie 207 --------if 207 --------in 195 --------11 195 --------Is 194 --------It 201 -----— mk 205 --------na 196 --------ne 200 -------- nf 196 --------nh 197 -------- nr 210 --------pl 200 — — — pm 202
452 Предметный указатель ро 196 ps 213 rt 205 — — — so 222 sp 194, 197 ta 199 tc 200 ti 195 tl 201 tm 222 vs 199, 214 ' wh 203 201 » 216 — /& 216 Запросы редактора vi 61, 66, 430 — аннулирование изменений 64 вставка 63 — выход 61, 63, 65 — дозапись 63 — копирование 64 G 62 — — — тар 70 о 63 — р 64 Зарезервированные слова, С 112 Измерение производительности 146 Иллюстрации, nroff 226 Имена макрозапросов, nroff 202 Инициализация переменных, С 136 Интерпретация пробелов, sh 91 Информация о файдах 41 Исключение литеры, vi 63 — оглавления 26, 167 — повторяющихся строк 260 — слова, vi 63 — строки, vi 63, 65 — файла 26 Использование дискового прост- ранства 38 Исправление ошибок при вводе 19, 25 Карта памяти, adb 153 Квадратные скобки, ed 55 Клавиша прерывания 17, 20, 34 Клавиша break 185 — del 20, 34, 185 , ed 57 — esc, vi 63 Класс памяти, С 135 — auto 135 extern 135 register 135 Идентификатор владельца 165. См. также Идентификатор пользо- вателя Идентификатор группы 179 действительный 182, 369, 377, 380, 388 эффективный 182, 377, 380, 388 . — пользователя 179 действительный 182, 369, 377, 380, 388 эффективный 182, 187, 377, 380, 385, 388 — процесса 380 Идентификатор, С 111 Изменение владельца файла 164 — оглавления 24 ** полномочий файла 163 static 135 typedef 135 Ключевые слова, С 112 Код ASCII 42, 112, 113, 258, 309, 447 — EBCDIC 112, 309 — ответа системных функций 373 Количество параметров argc 155, 182, 184, 378 Колонки, nroff 199 Колонтитулы, nroff 201, 203, 204 Команда 18, 71 — встроенная 100 —, опции 154 — фоновая 27, 38, 99, 182 — adb 149, 300 — аг 145, 300 — at 39, 281, 301
Предметный указатель 453 — awk 247, 302 — basename 90, 302 — break 101, 263 — cal 19, 302 — calendar 40, 303 — case 74, 75 — cat 25, 44, 303 — cb 303 — cc 105, 111, 141, 145, 147, 303 — cd 24, 80, 101 — ch dir 101 — chmod 72, 163, 305 — cmp 252, 306 — col 198, 234, 306 — comm 307 — continue 101 — cp 25, 27, 44, 170, 307 — create 74 — crypt 308 — date 18, 309 — dd 155, 309 — deroff 310 — df 38, 311 — diction 234, 311 — diff 253, 311 - du 37, 312 — dw 83 — echo 30, 313 — ed 45, 313 — egrep 318, — elif 83 — eqn 23, 234, 313 — eval 93, 101, 280, 281 — exec 97, 101, 280 — exit 95, 101 — explain 311 — export 32, 88, 101 — expr 82, 91, 314 — fgrep 318 — field 261 — file 40 —• find 40, 316 — f 77, 315 — grep 41, 254, 264, 318 — if 81, 82 — join 255, 320 — kill 38, 320 - Id 108, 321 — learn 23, 323 - lex 261, 323 - lint 116, 144, 156, 324 - In 167, 326 — login 17, 44, 101, 158, 326 - look 327 — lookbib 239, 339 — lorder 108, 146, 327 - Ipr 327 - Is 27, 41, 176, 327 — mail 33, 44, 329 — make 142, 330 — man 21, 44, 86, 87, 330 — mesg 36, 331 — mkdir 26, 44, 167, 331 — mklock 168 — mv 26, 27, 44, 331 — neqn 313 — newgrp 102, 165, 332 — nice 38, 332 — nm 148, 332 — nohup 38, 96, 99, 333 — nroff 193, 362 — od 42, 106, 333 — passwd 19, 334 — pr 42, 334 — prof 147, 335 — prompt 263 - ps 28, 37, 179, 336 - ptx 237, 337 — pubindex 339 — pwd 24, 89, 339 — ranlib 146, 339 - read 97, 102, 263 — readonly 88, 102 — refer 238, 339 — rm 26, 44, 341 — rmdir 26, 44, 167, 341 — sdb 342 — sed 257, 347 — set 85, 87, 102 — sh 72, 85, 350 - shift 82, 102 — size 147, 351
454 Предметный указатель — sleep 351 — sort 258, 351 — spell 240, 353 — strip 147, 354 — style 240, 356 — stty 20, 43, 185, 354 — tabs 20, 357 — tail 357 — tar 43, 357 — tbl 241, 359 — test 81, 360 — time 360 — times 102 — touch 143, 361 — tr 260, 361 — trap 95, 103, 362 — troff 362 — tsort 363 — umask 103, 163 — uniq 260, 364 — units 364 — uucp 35, 259, 365 — vi 366 — wait 103 — wc 28, 246, 367 — who 18, 29, 367 — write 36, 367 — yacc 261, 368 — , 101 — ; 89, 96, 101 Командная процедура 72 Командный файл 71, 72 Комментарий, G 111 —, nroff 194, 216 —, sh 31 Компилятор С» См. Команда сс Компилятор компиляторов уасс 261 Компиляция программы, С 105, 111, 132, 141 Конвейер 28, 179 Конец файла 25, 46, 106, 160 Константа, G — — восьмеричная 113 -----десятичная ИЗ ----- длинная 113 — — литерная 113 ----символическая 140 ----с плавающей точкой 114 ----текстовая 106, 113 — — целочисленная 113 ----шестнадцатеричная 113 ----EOF 106, 137 ----NULL 137 Константное выражение, С 120 Конструкция # define, G 108, 132 — # include, G 106, 133 — &&, sh 84 — ||, sh 84 Контекстный поиск, ed 50 Контрольная точка, adb 152 Копирование строк, ed 48 ----, vi 64 — файлов 25, 170 Коэффициенты, vi 68 Курсор, vi 61 Лексема, С 132 Лексический анализатор lex 261 Линии, nroff — — вертикальные 206 ----горизонтальные 206 Литера возобновления AQ 21, 177 — отмены @ 20, 177 — приостановки AS 177 — пусто 113, 124 — стирания # 20, 177 — Л/ 177 Литеры неграфические, ed 59 — специальные, G 113 ----, ed 48, 53, 54, 55, 56, 58 ----, sh 31, 78, 92 — управляющие 21 Ловушка, nroff 203 Макро, С 132 — । nroff 201 Макробиблиотека, nroff 218 Маска доступа umask, 103, 167 Массивы, G 123 ----инициализация 136 — — многомерные 124 Массивы, awk 251
Предметный указатель 455 Металитера &, 28 Металитеры, sh 31, 93 Метки, С 121 Монопольный доступ к файлу 283 — /lib 24 — /tmp 170 — /usr 24 Ограничители, ed 57 Окно, vi 61 Наложение литер, nroff 216 Нейтрализация сбоев, vi 68 Неудачное завершение команды 94 Нижний индекс, nroff 208, 235 Новая строка, 20, 31, 57 Новости дня 18 Номер ошибочной ситуации 161 — процесса 28, 37, 39, 79 — страницы, nroff 204 — текущей страницы, nroff 204 — фонового процесса 79 Оператор, С пустой 125 составной 119, 134 условный 119 цикла 120 break 120, 121 continue 122 default 120 do 121 for 108, 121 goto 121 if 108, 119 Обнаружение различий в файлах 253 Оболочка 15, 16, 71 — интерактивная 94, 100 —, команды 71 Обработка ошибочных ситуаций, С 139 — сигналов 95, 187 Обработчик сигнала 187 Образ процесса 179 Образец 246 —, awk 249 —, ed 50, 55 —, sh 29 Обратная косая черта 20, 42, 59, 77, 92, 194 Общие строки 252 Объединения, С 130 Объекты, vi 67 Оглавление 16 — исключение 167 — корневое 23 — рабочее 24, 370 — регистрационное 24 — родительское 23, 26 — создание 167 — текущее 24, 80, 370 — /bin 24 — /etc 24 return 122 switch 120 while 107, 121 Операции, C 114 арифметические 110, 114 вычитание 114 деление 114 получение остатка от де- ления 114 сложение 114 умножение 114 запятая 115 логические 115 отношения 114 поразрядные 115 дополнение 117 И 115 ИЛИ 115 исключающее ИЛИ 115 — — присваивания 116 сдвига 115 сравнения на равенство 115 унарные 117 косвенность * 117 логическое отрицание 117 преобразование типа 117 — sizeof 117 условная 116 Операция, adb 150
456 Предметный указатель Описание функции, С 122 Определение константы, G 132 — функции, С 122 Опции, 154 Открытие файла 158 Отладка командных процедур 85 — С-программ 148 Отладчик adb 148, 411 — sdb 148, 342 Отмена специальных значений ли- тер, ed 56 , sh 31, 91, 92, 93 Отступ, nroff 221 временный 195 текущий 211 Отступ, vi 67 Оформление страниц, nroff 225 Ошибка шины 186 MAIL 79 PATH 80, 273 PSI 32, 81 PS2 32, 81 TERM 60 $ # 73 $ * 73 Переменная, С environ 184, 378, 400 еггпо 188 sys_nerr 402 Переменные, С автоматические (динамиче- ские) 136 внешние 135, 149 внутренние 135 статические 136 Переменная, awk FILENAME 248 Параметр — ключевой, sh 87 — макро, С 132 — позиционный, sh 72, 81, 87 — фактический, С 123 — формальный, С 122, 123, 124 Параметры — запросов, nroff 194 — командной процедуры 72 —- команды 19, 21, 27, 154 — терминала 17, 43 — функции, С 118, 122, 123 Пароль — изменение 19 — использование 18 Переадресация ввода-вывода 28, 98 — диагностики 99 Перевод строки 20 — формата, С 113 , ed 59 Передача параметров, С 123 Переименование оглавления 26 — файла 26 Переменная оболочки 77 CDPATH 80, 101 НОМЕ 80, 91, 264 IFS 81 FS 248 OFS 248 RS 248 Переменные специальные sh 78 Перестановка строк, ed 47 Пересылка текста, ed 47 , vi 64 Перехват сигналов 187 Подготовка документов 190 Подпрограммы ввода-вывода, С 106 Подпрограммы, С asctime 304 call ос 400 cl ear err 396 — — ctime 394 fclose 395 fdopen 397 feof 396 — ferror 396 fflush 395 fgetc 399 fgets 400 — — fileno 396 fopen 137, 397 fprintf 404 — — fputc 406 — fputs 407
Предметный указатель 457 -----fread 398 ----- free 129, 400 -----freopen 397 -----fscanf 407 -----fseek 398 -----ftell 398 -----fwrite 398 -----getc 399 -----getchar 106, 399 -----getenv 155, 184, 399 -----gets 400 — — getw 399 -----gmtime 394 -----index 411 -----local time 394 -----longjmp 121, 139, 410 -----malloc 129, 400 -----mktemp 170, 402 -----monitor 402 -----pclose 403 -----perror 402 ----- popen 403 -----printf 105, 107, 110, 138, 404 -----putc 406 -----putchar 106, 406 -----puts 407 -----putw 406 -----realloc 400 -----rindex 411 -----rewind 398 -----scanf 138, 407 -----setbuf 409 -----setjmp 121, 139, 410 — — sprintf 404 -----sscanf 407 -----strcat 411 -----strcmp 411 -----strcpy 411 -----strlen 170, 411 -----strncat 411 -----strncmp 411 -----strncpy 411 -----system 183, 188 -----timezone 394 -----ungetc 412 Подстановка команд, sh 89 — параметров (переменных), sh 76, 78, 88 Поиск — в оглавлении 40 — в файловой системе 40 по образцу, ed 50 --------, vi 62 Поле записи 245 Полномочия файла 161, 163 Полный дуплекс 17, 176 Порождение имен файлов, sh 29, 92 Порядок выполнения операций, С 118 Посылка сигнала 186 Поток 137, 411 *- stderr 137, 411 — stdin 137, 411 — stdout 137, 411 Почта 34 Правила области действия, С 135 — преобразования значений, С 117 Предложение, vi 67 Преобразование литер 260 Препроцессор С 132 Прерывание страниц, nroff 200, 203 — трассировочное 185 Прерывание, ed 57 Прерывание, sh 32. См. также Сигнал прерывания Приглашение оболочки 32, 81 ---, G 118 Приоритет операций, adb 150 Пробел, sh 81, 91 Проверка типов, С 144 Продвижение окна, vi 61 Профилирование, G 146 Процесс 16, 97, 179 — порожденный (потомок) 180 — приоритет 332, 386 — родительский 180 — состояние 336 — статус завершения 392 — фоновый 188 Путь поиска 80, 101 Разбиение строки, ed 59
458 Предметный указатель Раздел, vi 67 Разделитель входных записей, awk 248 ----полей, awk 248 — выходных полей, awk 248 Размер литер, nroff 211 ----, troff 213 — файла 162 Разрешающая способность, nroff 211 1--------по вертикали 211 —--------по горизонтали 211 Разрыв связи с терминалом 178 — строки, nroff 196, 207 Расстояние между строками, nroff 214 Расстояния, nroff 198 Регистрационное имя 17 Регистры, nroff 208 * — текстовые 208 — числовые 209 Редактирование совокупности фай- лов, vi 68 — строк, ed 47 ----, vi 63 Редактор — пакетный sed 257, 347 — связей id 146 — экранный vi 60, 366, 430 — ed 45, 313, 416 Режим без выравнивания строк nroff 196 — без заполнения строк, nroff 196 — ввода «сырой» 354 • — вставки, ed 49 — дозаписи, ed 46 ----, vi 63 — доступа к файлу 159 — дуплексный 176 — с заполнением строк, nroff 196 Руководство для программиста си- стемы UNIX 21 Сдвиг на полстроки, nroff 208 •— по вертикали, nroff 204 по горизонтали, nroff 204 Сегмент данных 180 — стековый 180 Селектор, awk 247 Сигнал 94, 185 — выхода 94, 99, 177, 185 — зависания 94, 99, 185 — игнорирование 187 — от таймера 186, 370 — прерывания 18, 94, 95, 99, 177, 186 — программного завершения 94, 186, 320 — разрыва связи 178 — уничтожения 94, 186 — SIGALRM 186, 370 — SIGBUS 186 — SIGEMT 185 — SIGFPE 186 — SIGH UP 185 — SIGILL 185 — SIGINT 185 — SIGIOT 185 — SIGKILL 186 — SIGPIPE 186 — SIGUIT 185 — SIGSEGV 186 — SIGSYS 186 - SIGTERM 186 — SIGTRAP 185 Синтаксический анализатор уасс 261 Системные функции ----коды ответа 373 ----access 369 ----alarm 369 ---- brk 180, 370 ----ch dir 370 ---chmod 371 ---- close 161, 372 ----creat 166, 372 ----dup 98, 159, 179, 372 ----dup2 372 ---- exec 180, 182, 184, 377 ----execl 182, 377 ----execl e 378 ---- execv 182, 377 •---execv e 184, 378
Предметный указатель 459 -----exit 183, 379 -----fork 97, 180, 188, 379 -----fstat 159, 172, 389 -----ftime 390 -----getegid 379 -----geteuid 379 -----getgid 179, 379 — ~ getpid 379 ----- getuid 179, 379 -----gtty 94, 17Я, 380 -----ioctl 177, 178, 380 -----kill 186, 385 -----link 167, 385 -----Iseek 171, 385 ----- nice 386 -----open 159, 386 ----- pause 186, 387 -----pipe 178, 387 -----profil 387 -----read 137, 159, 177, 388 — — sbrk 370 -----seek 172 -----setuid 388 -----signal 187, 388 -----stat 172, 389 -----stty 178, 380 -----time 390 -----times 391 -----umask 391 -----unlink 167, 392 -----wait 179, 181, 392 -----write 160, 392 Скорость ввода-вывода 17 Слово, sh 27, 98 —, vi 62 Смена шрифта, troff 213 Смещение страницы текущее, nroff 211 Соглашения о параметрах 154 — о сигналах 99, 188 Соединение записей 255 Создание — временного файла 170 — оглавления 26, 167 — процесса 180 — ссылки на файл 167 — файла 25, 46 — файла-замка 167 Сообщения с других терминалов 36 Сопоставление с образцом, ed 54, 55 --------, grep 254 Сортировка — в лексикографическом порядке 258 — в числовом порядке 258 Сортировка и слияние файлов 258 Составное имя файла 23 Состояние — процесса 37 — файла 172 Сохранение программного сегмента 305 Список команд, sh 74 — параметров, ограничение 183 — процессов 37 Сравнение файлов 252 Среда выполнения команды 97, 99 Среда (процесса) 87, 184, 326 Среда выполнения, nroff 216 Средства обработки данных 233, 244 — произвольного доступа к файлу 158, 171 — связи между пользователями 33 Стандартная библиотека ввода-вы- вода stdio 137 ---С (libc) 145 Стандартная функция, awk 251 Стандартный файл ввода stdin 25, 28, 137, 158, 160 ---вывода stdout 25, 28, 137, 158, 160 ---диагностики stderr 28,137,158 Статус завершения команды 78 — — процесса 184, 392 Страница, nroff — конец 203 — начало 203 — нечетная 207 — четная 207 Структуры, С 127 Суперпользователь 165, 332, 334, 371, 373
460 Предметный указатель Таблица процессов 180 — символов, С 147 Табуляция 18, 20 —, С 113 —, ed 59 —, nroff 199 Текущая строка, ed 48 -----, vi 61 Текущий адрес, adb 149 Терминал управляющий 176 Тип данных массив, С 123 -----char, С 104, 112 -----double, С 104, 112 -----float, С 104, 112 -----int, С 104, 112 Тип терминала, vi 60 — файла 175 Типы данных, С 104, 112 Точка входа (в программу) 182 Точность, С — двойная 112 — обычная 112 Транспортер 28, 158, 178, 186 — разорванный 186 Трассировка выполнения 85 Удаление суффикса 90 Указатели, С 124, 125 Указатель — предметный 227, 231 — циклический 237 Уничтожение оглавления 167 — файла 26, 167 Управление курсором, vi 61, 65 — левым полем, nroff 195 — окном, vi 65 — полями, nroff 195 — правым полем, nroff 195 — страницами, nroff 200, 203 Управляющие конструкции, sh 82 -----— case 74 --------if 83 Управляющий терминал 176 Условная компиляция, С 133 Условное форматирование, nroff 206 Установка внутренних переменных, vi 69 — идентификации группы 162, 182 --------ПрИ выполнении 377 ----пользователя 162, 182 --------при выполнении 377 — параметров терминала 20 — указателя текущей позиции в файле 171 Файл архивный 145 — библиотечный 145 —, время создания 164 — выполнимый 72 — групп /etc/group 165, 166 —, доступность 369 — заголовков 106, 137, 141, 142 ----stdio.h 137 Файл-замок 167, 283 Файл, запись 159 — исходный 141 — объектный 141 — обычный 15 — паролей /etc/passwd 165 —, полномочия 161 —, размер 162 —, режим 159 — специальный 16, 175 ----блочный 175 ----литерный 175 ----/dev/null 181, 182 ----/dev/tty 176 —, ссылки 162 — целевой (make) 142 —, чтение 159 — a.out 105, 141, 146, 149, 182 — core 145, 148, 149, 177, 185, 342 — dead.letter 34 — ed.hup 57 — errno.h 161 — /etc/motd 25 — Makefile 142 — mbox 34 — mon.out 147 — .profile 32, 79, 100 Файловая система 15, 38
Предметный указатель 461 Фильтр 28 — преобразования литер 260, 361 — сопоставления с образцом 29, 254, 318 — сортировки 29, 258, 351 Формат, С ПО, 138 ----%с 138 ----%d 138 — _%f 138 ----%о 138 ----%s 138 ----%х 138 ----% % 138 Форматирование библиографиче- ских ссылок 238 Форматная печать, С 138 ----, awk 250 Форматор nroff 190. См. также Команда nroff — troff 190. См. также Команда troff, Форматор nroff Функции, С 122. См. также Подпро- граммы, С — рекурсивные, С 123 — системные. См. Системные функ- ции Функции, awk. См. Встроенные функции, awk Функции, nroff 194 \d 204 \е 216 \f 213 \h 204 \n 209 \o 208 — — \s 213 — — \u 204 \v 204 \w 205 Функция main C 105, 106, 155 Характеристики терминала 43 Цепочки, nroff 208 Циклы, sh 73 -----, for 73, 74 -----, until 82 ------, while 82 Язык С 104 ----- структура 134 -----1-значение 116 -----г-значение 116 Ярлык структуры, С 128
ОГЛАВЛЕНИЕ Предисловие редактора перевода . , .............................. 5 Предисловие...................................................... 6 Глава 1. Введение................................................ 10 1.1. Историческая справка.................................... 11 1.2. Среда программирования.................................. 14 1.3. Концепция системы UNIX . .............................. 15 Глава 2. Начальные сведения...................................... 17 2.1. Вход в систему......................................... 17 2.2. Команды................................................ 18 2.3. Характеристики терминала............................... 19 2.4. Документация.......................................... 21 2.5. Файловая система....................................... 23 2.6. Оболочка............................................... 27 2.7. Наиболее употребительные команды.............. . . . 33 Глава 3. Редактирование файлов ................................. 45 3.1. Редактор ed . . . ..................................... 45 3.2. Редактор vi........................................... 60 Глава 4. Оболочка................................................ 71 4.1. Командные процедуры.................................... 72 4.2. Дополнительные возможности............................. 87 4.3. Встроенные команды . . ................................. 100 Глава 5. Язык программирования С . ............................ 104 5.1. Примеры программ на языке С • . ...................... 105 5.2. Описание языка........................................ 111 5.3. Организация программ и управление программами......... 141 5.4. Отладка С-программ................................... 148 Глава 6. Программирование в системе UNIX....................... 154 6.1. Соглашения о параметрах............................... 154 6.2. Базисные средства ввода-вывода........................ 157 6.3. Дополнительные сведения о файловой системе............ 161 6.4. Дополнительные возможности ввода-вывода............... 166 6.5. Процессы............................................ 179 6.6. Сигналы и прерывания.................................. 185 Глава 7. Подготовка документов................................. 190 7.1. Форматоры текстов nroff и troff................... . 190 7.2. Получение итогового документа........................ 228 7.3, Средства обработки текстовых документов............... 233
Оглавление 463 Глава 8. Средства обработки данных........................... 244 8.1. Краткое описание средств............................. 245 8.2. Простейшие примеры................................... 262 8.3. Обработка результатов соревнований по теннису........ 272 8.4. Реализация команды field............................. 297 Приложение 1. Команды ... ................................ 300 Приложение 2. Системные функции........................... 369 Приложение 3. Подпрограммы из библиотеки языка С.......... 394 Приложение 4. Запросы отладчика adb....................... 413 Приложение 5. Запросы редактора ed........................ 416 Приложение 6. Командный язык.............................. 418 Приложение 7. Запросы форматора troff..................... 421 Приложение 8. Команды редактора vi........................ 430 Приложение 9. Макробиблиотека............................. 434 Приложение 10. Библиотека макроопределений ms . . . ....... 441 Приложение И. Набор литер ASCII . ....................... 447 Литература................................................... 448 Предметный указатель.................................... » . 450
Уважаемый читатель! Ваши замечания о содержании книги, ее оформлении, качестве пере- вода и другие просим присылать по адресу: 129820, Москва, И-110, ГСП, 1-й Рижский пер., д. 2, издательство «Мир». Монография Стив Баурн ОПЕРАЦИОННАЯ СИСТЕМА UNIX Научный редактор М. В. Хатунцева Мл. научн. редактор Р. И. Пяткина Художник Н. Я- Вовк Художественный редактор В. И. Шаповалов Технический редактор И. И. Володина Корректор Т. П. Пашковская ИБ № 5903 Сдано в набор 9.12.85. Подписано к печати 26.05.86. Формат бОХЭО1/!#- Бумага кн,- журн. Печать высокая. Гарнитура литературная. Объем 14,5 бум. л. Усл. печ. л. 29,0. Усл. кр.-отт. 29,51. Уч.-изд. л. 25,59. Изд. № 1/3953. Тираж 25000 экз. Зак. 1953. Цена 1 р. 90 к. ИЗДАТЕЛЬСТВО «МИР» 129820, ГСП, Москва, И-110, 1-й Рижский пер., 2 Ордена Октябрьской Революции и ордена Трудового Красного Знамени МПО «Первая Образцовая типография» имени А. А. Жданова Союзполиграфпрома при Государствен- ном комитете СССР по делам издательств, полиграфии и книжной торговли. 113054, Москва, Валовая, 28
1 p. 90 к.