Брайан Керниган - UNIX — универсальная среда программирования
Интерпретатор дает вам такие средства, как циклы, переключение ввода-вывода с помощью < и >, порождение имен файлов с помощью *, причем применение этих средств единообразно во всех программах. Некоторые средства, например командные файлы и программные каналы, на самом деле обеспечиваются ядром, но язык shell предоставляет естественную запись для их создания. Они не только удобны, но и увеличивают мощность системы в целом.
Базой для интерпретатора служит ядро системы UNIX, например, хотя интерпретатор и определяет конвейеры, именно ядро осуществляет передачу данных по ним. Способ, которым система обрабатывает выполняемые файлы, позволяет программировать командные файлы так, чтобы они выполнялись подобно оттранслированным программам. Пользователь не должен думать о том, что это командные файлы, — для передачи их на выполнение не требуется специальная команда типа RUN. Сам интерпретатор является программой, а не частью ядра. Его можно настраивать, расширять и обращаться с ним, как с любой другой программой. Такой подход не является уникальным, но здесь он реализован полнее, чем где бы то ни было.
В гл. 5 мы вернемся к теме программирования на языке shell, а пока запомните: вне зависимости от того, как вы работаете с интерпретатором, вы программируете на его языке (чем в основном и объясняются его достоинства).
Историческая и библиографическая справкаНа языке интерпретатора программируют с незапамятных времен. Сперва были отдельные команды для if, goto и меток, а команда goto выполнялась путем просмотра входного файла от его начала до нужной метки. (Поскольку невозможно читать заново через программный канал, нельзя было и передавать по программному каналу в командный файл, использующий структуры управления.)
Седьмая версия интерпретатора была создана С. Боурном, которому оказал помощь и идейную поддержку Д. Мэшей. Как вы увидите в гл. 5, здесь есть все необходимое для программирования. Кроме того, реорганизована работа с входным и выходным потоками: теперь можно без ограничения переключать ввод-вывод из командных файлов и в них. Неотъемлемым свойством интерпретатора является обработка метасимволов в именах файлов; в ранних версиях, которые остались лишь на очень маленьких машинах, она реализовывалась отдельной программой.
Другой вариант интерпретатора, с которым вы могли встречаться (а может быть, вы предпочитаете с ним работать) — csh, так называемый Си-shell, созданный Б. Джоем на базе интерпретатора шестой версии. По сравнению с интерпретатором Боурна этот интерпретатор лучше обеспечивает диалог. Он предоставляет средство "история", позволяющее повторять в сокращенной записи (возможно, с небольшим редактированием) предварительно введенные команды. Отличается также и синтаксис команд интерпретатора Джоя. Но, поскольку Си-shell, базируется на интерпретаторе ранней версии, в нем содержится меньше средств для программирования; это скорее диалоговый интерпретатор команд, чем язык программирования. В частности, исключена передача по программному каналу из (или в) командного файла со структурами управления.
Команда pick предложена Т. Даффом, а команда bundle — независимо А. Хьитом и Д. Гослингом.
Глава 4
Фильтры
Существует большое число программ UNIX, которые читают входной поток, выполняют простые операции над ним и записывают результат в выходной поток. Примерами могут служить программы grep и tail, выбирающие часть входного потока, sort, сортирующая его, wc, производящая подсчет в нем, и т.д. Такие программы называются фильтрами.
В настоящей главе обсуждаются наиболее часто используемые фильтры. Первой мы рассмотрим программу grep, сосредоточившись на более сложных шаблонах, чем описанные в гл. 1, а затем две другие родственные программы — egrep и fgrep. Далее вы познакомитесь с еще несколькими полезными фильтрами, включая tr, который предназначен для транслитерации символов, dd, предназначенный для работы с данными, полученными из других систем, и uniq — для обнаружения повторяющихся строк. Приводится дополнительная информация и о программе sort.
Конец главы посвящен двум преобразователям данных общего назначения, или программируемым фильтрам. Они называются так потому, что конкретное преобразование записывается как программа на некотором простом языке программирования. Различные программы могут породить совершенно разные преобразования. Речь идет здесь о программах sed ("stream editor" — потоковый редактор) и awk, имя которой составлено из начальных букв имен ее авторов. Обе программы получаются путем обобщения команды grep:
$ программа шаблон-действие имена_файлов...
которая сканирует последовательность файлов, ведя поиск строк, совпадающих с шаблоном, — если строка найдена, выполняется необходимое действие. Для команды grep, как и для редактора ed, шаблоном является регулярное выражение, а действие по умолчанию сводится к печати каждой строки, соответствующей шаблону.
В программах sed и awk обобщаются и шаблоны, и действия. Команда sed, производная от ed, выполняет "программу", состоящую из команд редактирования. Она пропускает данные из файлов через эту программу, выполняя для каждой строки команды из программы. Команда awk не так удобна, как sed, для манипуляций с текстом, но в ней предусмотрены арифметические операции, переменные, встроенные функции и язык программирования, схожий с Си. В данной главе не приводится полное описание обеих программ; оно есть в т. 2B справочного руководства по UNIX.
4.1 Семейство программ grep
В гл. 1 мы кратко упомянули о команде grep, а затем использовали ее в примерах. Конструкция
$ grep шаблон имена_файлов
проводит поиск в поименованных файлах или в стандартном входном потоке и выводит на печать каждую строку, в которую входит шаблон. Команда grep неоценима для поиска переменных в программах и слов в документах, а также для выбора части выходного потока программы:
$ grep -n variable *.[гл] Поиск variable в тексте на Си
$ grep From $MAIL Печать заголовков сообщений из почтовой
посылки
$ grep From $MAIL | grep -v mary Заголовки, которые получены не от
адресата mary
$ grep -y mary $HOME/lib/phone-book Поиск номера mary
$ who | grep mary Выяснить, работает ли mary в системе
$ ls | grep -v temp Имена файлов, не содержащих temp
Флаг -n инициирует вывод номеров строк, флаг -v меняет на противоположное значение условия, а флаг -y допускает сопоставление строчных букв из шаблона с прописными буквами из файла (но прописные буквы все-таки могут сопоставляться только с прописными).
Во всех рассматривавшихся до сих пор примерах проводился поиск обычных строк из букв и чисел. Но команда grep может искать и более сложные шаблоны: она интерпретирует выражения согласно простому языку для описания строк. С технической точки зрения шаблон представляет в некоторой степени ограниченную форму спецификаций строк, называемую регулярным выражением. Команда интерпретирует такие же регулярные выражения, как и редактор ed. На самом деле, эта команда была создана (за один вечер) прямым редактированием ed.
Регулярные выражения характеризуются тем, что ряду символов, таким, как * и т.п., приписывается специальное значение, используемое интерпретатором. Есть еще несколько метасимволов, но, к сожалению, с различными значениями. В табл. 4.1 показаны все метасимволы регулярных выражений, и мы кратко их здесь рассмотрим.
с Любой неспециальный символ c соответствует самому себе c Указание убрать любое специальное значение символа c ^ Начало строки $ Конец строки . Любой одиночный символ [...] Любой символ из ...; допустимы диапазоны типа a-z [^...] Любой символ не из ...; допустимы диапазоны n Строка, соответствующая n-му выражению (...) (только для grep) r* Нуль или более вхождений r r+ Одно или более вхождений r (только для egrep) r? Нуль или одно вхождение r (только для egrep) r1r2 За r1 следует r2 r1|r2 r1 или r2 (только для egrep) (r) Помеченное регулярное выражение r (только для grep); может быть вложенным (r) Регулярное выражение r (только для grep); может быть вложенным Никакое регулярное выражение не соответствует концу строкиТаблица 4.1: Регулярные выражения grep и egrep (в порядке убывания приоритета)