ОС UNIX с точки зрения пользователя СОДЕРЖАНИЕ 1. Введение 3 1.1. Обозначения 3 2. Основные понятия операционной системы UNIX 4 3. Пользователь 5 4. Организация файловой системы ОС UNIX 7 4.1. Типы файлов 7 4.2. Специальные файлы. Аппаратная структура станции БЕСТА 7 4.3. Общая структура файловой системы 9 4.4. Структура каталогов. Имена файлов 9 4.5. Монтирование файловой системы 10 4.6. Режим доспупа к файлам 12 4.7. Операции с файлами 12 4.7.1. Получение имени текущего каталога. Смена текущего каталога 12 4.7.2. Получение информации о файлах 13 4.7.3. Создание и удаление файлов 17 4.7.4. Копирование и перемещение файлов. Создание новой ссылки на файл 18 4.7.5. Вывод содержимого файлов 19 4.7.6. Смена владельца и режима доступа к файлу 19 4.7.7. Подсчет числа символов, слов и строк в файле 20 4.7.8. Поиск в файле заданного текста 21 5. Процессы 23 5.1. Выдача информации о процессах 23 5.2. Уничтожение процессов 24 5.3. Измерение времени работы процессов 24 5.4. Стандартный ввод, стандартный вывод, стандартный протокол 25 6. Терминал 26 7. Язык shell 28 7.1. Определения 28 7.2. Общий механизм выполнения команд 29 7.3. Примеры конвейеров 30 7.4. Примеры простейших shell-процедур 31 7.5. Переменные и аргументы shell-процедур 32 7.6. Служебные переменные shell'а 34 7.7. Окружение процессов 35 7.8. Подстановка результатов выполнения команд 38 7.9. Управляющие конструкции 38 7.10. Генерация имен файлов 42 7.11. Переназначение ввода/вывода 44 7.12. Экранирование 45 7.13. Специальные команды shell'а 46 7.14. Резюме 49 8. Некоторые полезные команды 50 8.1. Поиск файлов 50 8.2. Преобразование файлов в архивный формат 52 8.3. Обмен информацией со стримерной лентой 54 8.4. Удобные команды для работы с лентой 55 8.5. Работа с флоппи-диском MS-DOS 55 9. Резюме 58 Приложение A. Пользовательские команды ОС UNIX 59 Приложение B. Сводка синтаксиса пользовательских команд 62 1. ВВЕДЕНИЕ Данное руководство рассчитано на пользователей рабочей станции БЕСТА, имеющих программистский опыт, но не являющихся специа- листами по операционной системе UNIX. Цель руководства - дать общее представление о станции БЕСТА и ее базовом программном обеспечении - ОС UNIX V.3, Интегрированной Среде Разработки Программ (ИСРП), графических и сетевых системах. Основное вни- мание уделено операционной системе, которая рассматривается с трех точек зрения - пользователя, программиста и администрато- ра. Кроме того, руководство призвано помочь сориентироваться в документации по рабочей станции БЕСТА. Руководство рассчитано на двухпроходное изучение. При первом чтении рекомендуется пропускать технические детали (например, описание опций) и пытаться уловить суть. При втором чтении сле- дует вникнуть в детали и выполнить приведенные примеры. 1.1. Обозначения При описании синтаксиса команд ОС UNIX в квадратные скобки зак- лючаются необязательные аргументы. Многоточие означает повторе- ние предыдущего аргумента произвольное число раз. Предполагает- ся, что пользователь взаимодействует с программой-оболочкой, которая называется shell. Отдельные элементы командной строки, передаваемой shell`у, должны разделяться пробелами. Для редак- тирования командной строки разрешается пользоваться только кла- вишей забоя. Документация по ОС UNIX состоит из Справочников и Руководств. В тексте данной публикации встречаются ссылки на статьи из Спра- вочников. Ссылки записываются в виде название_статьи(номер_раз дела). Пронумерованные разделы расположены в следующих Справоч- никах: Раздел 1 - в Справочнике пользователя. Разделы 2, 3, 4, 5 - в Справочнике программиста. Разделы 1M, 7, 8 - в Справочнике администратора. Руководства содержат подробное изложение некоторых тем, затро- нутых в Справочниках, но нуждающихся в более подробном разъяс- нении. Такими темами являются, например, межпроцессное взаимо- действие, управление терминалами, работа с разделяемыми библио теками и т.п. Отдельные тома документации рабочей станции БЕСТА посвящены Ин- тегрированной Среде Разработки Программ, а также графическому и сетевому обеспечению. 2. ОСНОВНЫЕ ПОНЯТИЯ ОПЕРАЦИОННОЙ СИСТЕМЫ UNIX Рабочие станции БЕСТА функционируют под управлением операцион- ной системы (ОС) UNIX. Характерной чертой ОС UNIX является то, что эта операционная система поддерживает многопользовательский режим работы. Станция БЕСТА в стандартной конфигурации способна одновременно обслуживать 9 пользователей. Основными понятиями ОС UNIX являются: Пользователь. Файл. Процесс. Терминал. 3. ПОЛЬЗОВАТЕЛЬ Каждый зарегистрированный пользователь ОС UNIX имеет входное имя (для регистрации новых пользователей рекомендуется пользо- ваться командой nuser, см. далее). Пользователь, с входным име нем root, называется суперпользователем; он имеет права на лю- бые действия. Другие пользователи называются обычными. Для входа в систему нужно в ответ на приглашение |login: ввести свое входное имя (и, быть может, пароль). После нормального входа в систему на экран будет выдано пригла- шение к дальнейшей работе. Для обычных пользователей, в качест- ве приглашения, используется пара символов |$ (доллар и пробел), для суперпользователя - пара символов |# (знак номера и пробел). Не рекомендуется злоупотреблять работой в системе под именем root, поскольку можно нечаянно удалить нужную информацию (обыч ному пользователю на это не хватит прав). Каждый пользователь ОС UNIX принадлежит некоторой группе. Отме- тим, что члены группы sys могут стать суперпользователями, вы- полнив команду |bson Другие обычные пользователи лишены такой возможности. И входному имени, и имени группы соответствуют числовые иденти фикаторы (номера пользователя и группы), которыми система опе рирует во всех случаях, кроме первоначальной идентификации пользователя. Чтобы во время сеанса работы узнать свои входное имя, номер, а также имя и номер группы, нужно воспользоваться командой |id Например, если Вы вошли в систему под именем guest, команда id выдаст такую информацию: |uid=100(guest) gid=13(people) Пользователь guest имеет числовой идентификатор 100, входит в группу people, числовой идентификатор которой - 13. Если Вы вошли в систему под именем root, то команда id выдаст следующее: |uid=0(root) gid=3(sys) Строго говоря, именно числовой идентификатор 0 характеризует суперпользователя. Чтобы узнать, какие пользователи и за какими терминалами рабо тают в данный момент в системе, можно воспользоваться командой |who Выдача команды who может выглядеть, например, так: |user1 console Oct 3 13:16 |user2 tty2 Oct 3 10:00 |user3 tty3 Oct 3 11:44 |user4 tty6 Oct 3 11:47 (правая колонка означает время входа в систему). Упомянем еще такие команды, как write(1), wall(1M), whodo(1M). Для установки или смены пароля применяется команда |passwd Команда запрашивает у обычных пользователей старый пароль (если он был), а затем дважды запрашивает новый. После первого запро- са делается проверка на соответствие нового пароля техническим требованиям - пароль должен содержать не менее шести символов, в числе которых обязательно должны быть буквы, цифры и знаки. Когда новый пароль вводится во второй раз, две копии нового па- роля сравниваются. Если они не совпали, цикл запроса нового па- роля повторяется, но не более двух раз. Чтобы закончить сеанс работы в системе, нужно нажать CTRL+D, то есть, удерживая нажатой клавишу CTRL, нажать еще D. 4. ОРГАНИЗАЦИЯ ФАЙЛОВОЙ СИСТЕМЫ ОС UNIX Файловая система ОС UNIX имеет иерархическую структуру. Выделен корневой каталог, содержащий файлы и другие каталоги. Послед- ние, в свою очередь, содержат файлы и каталоги, и т.д. 4.1. Типы файлов В ОС UNIX понятие файла охватывает все, что может содержать, потреблять и/или поставлять информацию, в том числе и внешние устройства, такие как терминалы, диски и т.п. Файлы бывают пяти типов: Обычные. Каталоги. Каналы. Символьные специальные. Блочные специальные. Понятие обычного файла поясняться не будет. Каталог - это файл, содержащий ссылки на другие файлы. Канал можно представлять себе в виде транспортера, с одной сто роны которого находится поставщик (процесс, который пишет в ка- нал), а с другой - потребитель (процесс, читающий из канала). Специальные файлы соответствуют аппаратным компонентам компь- ютера. С символьными специальными файлами можно обмениваться порциями информации произвольного размера. Пример устройства, которому соответствует символьный специальный файл - терминал. С блочными специальными файлами можно обмениваться только пор- циями информации, размер которых кратен некоторой величине - размеру блока. Пример устройства, которому соответствует блоч- ный специальный файл - магнитный диск. 4.2. Специальные файлы. Аппаратная структура станции БЕСТА Рассмотрим аппаратную организацию станции БЕСТА и специальные файлы, соответствующие ее компонентам. Сразу же отметим, что все специальные файлы располагаются в каталоге /dev и его под- каталогах. В стандартной конфигурации станция БЕСТА содержит 8 плат - по четыре в верхнем и нижнем рядах. Рассмотрим сначала платы верх- него ряда, затем нижнего. Левая плата, в верхнем ряду, называется арбитром шины. Эта пл та поддерживает 25-контактный последовательный порт RS232, ко- торому соответствует символьный специальный файл /dev/lp. Кроме того, плата поддерживает параллельный порт в стандарте CENTRO NICS (файл /dev/pit ). Принтер (последовательный или параллель- ный) рекомендуется подключать к этой плате. Следующая плата называется платой терминального ввода/вывода. Она поддерживает восемь 9-контактных портов RS232. Символьные специальные файлы, соответствующие этим портам (сверху вниз) /dev/tty4, /dev/tty5 , ..., /dev/tty11. К этим портам обычно подключаются терминалы. Третья плата, в верхнем ряду, обслуживает магнитные накопители - винчестерский диск, стримерную ленту, флоппи-диск. К одной плате можно подключить до шести устройств, но не более четырех устройств одного вида. Ленте соответствует символьный специальный файл /dev/mt. Отме- тим, что стандартными системными средствами стримерную ленту можно читать/писать только с начала, то есть на ленте нельзя организовать несколько разделов. С точки зрения ОС UNIX, магнитные диски могут выступать в двух качествах - как бесструктурные (неформатированные) устройства и как блочные (форматированные). Символьные специальные файлы, соответствующие неформатированным дискам, находятся в каталог /dev/rdsk, блочные - в каталоге /dev/dsk. Всему винчестерскому диску соответствует файл hd0s7 (в обоих каталогах). Физический диск может быть поделен на логические. Логическим дискам соответствуют специальные файлы hd0s0, hd0s1 и т.д. В стандартной конфигурации логических дисков три. Диск hd0s0, размером 50 Мб, хранит файлы, необходимые для работы ОС UNIX. На диске hd0s1, размером 220 Мб, располагаются пользова- тельские файлы. Наконец, диск hd0s2, размером 30 Мб, использу- ется как устройство подкачки (ОС UNIX поддерживает виртуальную память). Таким образом, общая емкость стандартно поставляемого винчестерского диска - 300 Мб. Если на станции установлен второй винчестерский диск, имя соот- ветствующих специальных файлов будет начинаться на hd1. Флоппи-диску соответствует несколько специальных файлов. Обыч- ному UNIX-флоппи-диску с размером блока 1 Кб и общей емкостью 800 Кб соответствует специальный файл fd. Аппаратура позволяет работать и с другими размерами блоков. Например, флоппи-диску с размером блока 512 байт, общей емкостью 360 Кб и файловой структурой MS-DOS соответствует специальный файл fd512PC. Рабо- та с флоппи-дисками MS-DOS будет подробно описана ниже. Отметим попутно, что в системе может быть определен диск в па- мяти, которому соответствует специальный файл rd. Четвертой и последней платой, в верхнем ряду, является плата процессора. На ней расположены процессор MC68020, сопроцессор вещественной арифметики MC68881 и устройство управления стра- ничной памятью MC68851. Кроме того, плата поддерживает 25-кон- тактный последовательный порт RS232, к которому подключается системная консоль. Имя соответствующего символьного специально го файла - /dev/tty1 или /dev/console. В нижнем ряду располагаются две платы памяти, общей емкостью 8 Мб. Физической памяти соответствует символьный специальный файл /dev/mem. Две последние платы - суть платы графического контроллера. 4.3. Общая структура файловой системы Каждая файловая система ОС UNIX содержит данные трех видов: Суперблок. Описатели файлов. Файлы. В суперблоке хранится сводная информация о файловой системе (в частности, размер и имя файловой системы, количество свободных блоков, описатель состояния и т.п.). Подробно структура суперб лока описана в статье fs(4). В описателях файлов содержится, по существу, вся информация о файле, кроме его содержимого, а именно: адреса блоков, в кото- рых располагается файл; размер файла; права доступа к нему; времена последнего доступа/модификации и т.п. Описатели нумеру- ются целыми числами. 4.4. Структура каталогов. Имена файлов Каталоги содержат ссылки на файлы. Каждая ссылка представляет собой пару: Имя файла (не более 14 символов). Номер описателя файла. На один файл (описатель файла) из одного или разных каталогов может быть несколько ссылок. Пример подобного файла - /dev/con- sole. Каждый каталог (даже пустой) обязательно содержит два элемента - ссылку на себя (имя .) и ссылку на вышележащий каталог (имя ..). Корневой каталог имеет имя /. Имена промежуточных каталогов в составном имени файла отделяются друг от друга и от простого имени символами /. Часть составного имени, до последнего симво- ла /, называется маршрутом. Примеры составных имен: |/unix |/usr/lib/terminfo/d/d211 |../fs.4 |./prog.for Первые два имени являются абсолютными, в них задан маршрут от корня файловой системы. Файл unix лежит в корневом каталоге, файл d211 - в каталоге /usr/lib/terminfo/d. Третье и четвертое - относительные имена, поскольку маршрут в них задан относи- тельно текущего каталога. Третье имя специфицирует файл fs.4, лежащий в иерархии файлов на один уровень выше, чем файлы теку- щего каталога. Последнее имя специфицирует файл из текущего ка- талога. Его можно было задать и проще: |prog.for Подчеркнем, что ограничение в 14 символов относится только к простому имени файла; составное имя может быть длиннее. Для корневого каталога имя .. ссылается также на корень. 4.5. Монтирование файловой системы В ОС UNIX должна постоянно присутствовать файловая система, на- зываемая корневой. Корневой каталог этой файловой системы явля- ется корнем всей файловой системы на данном компьютере. В стан- дартной конфигурации корневая файловая система расположена на диске /dev/dsk/hd0s0. Чтобы стала доступной другая файловая система, находящаяся, быть может, на съемном носителе, следует выполнить операцию монтирования, то есть установить соответст- вие между (пустым) каталогом, в уже смонтированной файловой системе (обычно корневой, но это не обязательно) и корнем новой файловой системы. Синтаксис операции монтирования таков: |/etc/mount специальный_файл каталог Здесь специальный_файл соответствует устройству, на котором хранится монтируемая файловая система. Типичным примером явля- ется монтирование файловой системы, расположенной на флоппи- диске: |/etc/mount /dev/dsk/fd /mnt Каталог /mnt - стандартный "дежурный" каталог для монтирования действительно сменяемых файловых систем. В начале работы системы диск с пользовательской информацией (его имя - /dev/dsk/hd0s1) монтируется на каталог /udd, поэтому абсолютные имена пользовательских файлов начинаются на /udd. После монтирования файлы новой файловой системы становятся дос- тупными, только в качестве префикса к их именам следует зада- вать имя каталога, на который было выполнено монтирование. Нап- ример, если файл на флоппи-диске назывался /subdir/file, то после монтирования на каталог /mnt к нему нужно обращаться как к /mnt/subdir/file. Файловую систему можно смонтировать только на чтение, если ука- зать опцию -r, например |/etc/mount -r /dev/dsk/fd /mnt В таком случае, файлы новой файловой системы можно только ч тать, изменить их будет невозможно. Если флоппи-диск защищен от записи, то смонтировать его удастся только на чтение. Для монтирования флоппи-диска (на чтение/запись) на каталог /mnt, вместо довольно длинного обращения к /etc/mount, можно воспользоваться командой |flon После того как работа с файловой системой закончена, ее следует размонтировать командой вида |/etc/umount каталог если монтирование выполнялось на указанный каталог. Например, в конце работы с флоппи-диском нужно воспользоваться командой |/etc/umount /mnt или ее более коротким аналогом |floff Делать это следует обязательно, так как иначе файловая система на флоппи-диске окажется в заведомо некорректном состоянии, а разрушения могут быть сколь угодно тяжелыми. Особенно неприятна ситуация, когда после записи на флоппи-диск без размонтирова- ния, одна дискета вынимается, а другая устанавливается. ОС UNIX буферизует дисковые блоки, и фактическая запись может затронуть флоппи-диск, установленный вторым. В результате испортится не один флоппи-диск, а два. Обратим внимание на следующее обстоятельство. Поскольку в ката- логе ссылка на файл задается номером его описателя, а нумерация локальна для каждой файловой системы (то есть по номеру описа- теля нельзя узнать, к какой файловой системе он относится), считается, что имеется в виду та файловая система, на которой расположен каталог. Таким образом, нет средств для организации ссылок между разными файловыми системами, то есть элементом ка- талога не может быть ссылка на файл, принадлежащий другой фай- ловой системе. 4.6. Режим доспупа к файлам По отношению к конкретному файлу, все пользователи делятся на три категории: Владелец файла. Члены группы владельца. Прочие пользователи. Для каждой из этих категорий режим доступа определяет права на операции с файлом, а именно: Право на чтение. Право на запись. Право на выполнение (для каталогов - право на поиск). Указанных видов прав достаточно, чтобы определить допустимость любой операции с файлами. Например, для удаления файла необхо димо иметь право на запись в соответствующий каталог. 4.7. Операции с файлами 4.7.1. Получение имени текущего каталога. Смена текущего каталога Чтобы узнать имя текущего каталога, следует воспользоваться ко- мандой |pwd Для перехода в другой каталог служит команда |cd каталог Например, чтобы сделать текущим каталог /tmp, можно употребить команду |cd /tmp Команда |cd .. осуществляет переход в каталог, вышележащий по отношению к те- кущему. 4.7.2. Получение информации о файлах Для выдачи информации о файлах всех типов служит команда |ls [опция ...] [файл ...] (напомним, что в квадратные скобки заключаются необязательные аргументы). Как правило, если в качестве файла задано имя ката- лога, то выводится информация обо всех содержащихся в нем фай- лах. Опции управляют порядком и степенью подробности выдаваемой ин- формации о файлах. Если опции не заданы, выводятся только имена файлов. Если не заданы файлы, выдается информация о файлах те- кущего каталога. Опция -l предписывает выводить подробную ин- формацию. Например, по команде |ls -l / может быть выдано следующее: |total 269 |drwxr-xr-x 2 bin bin 1504 Sep 18 13:06 bin |drwxr-xr-x 10 root sys 2608 Aug 22 19:13 dev |drwxr-xr-x 13 root sys 304 Oct 3 17:01 dss |drwxr-xr-x 11 root sys 2080 Oct 1 20:35 etc |drwxr-xr-x 4 root sys 464 Jun 19 1989 lib |drwxr-xr-x 2 root sys 1024 Mar 20 1989 lost+found |drwxrwxrwx 2 root sys 32 Jun 6 13:02 mnt |drwxr-xr-x 13 root sys 384 Oct 1 19:58 net |drwxr-xr-x 2 root sys 128 Mar 13 1990 shlib |drwxrwxrwx 2 sys sys 352 Oct 3 18:21 tmp |drwxrwxr-x 22 root sys 384 Sep 14 15:10 udd |-rwxr-xr-x 1 root sys 262438 Jun 26 09:20 unix |drwxr-xr-x 30 root sys 480 Oct 3 15:30 usr |drwxr-xr-x 9 root sys 2160 Aug 31 15:10 util Число в первой строке - есть суммарный размер (в блоках по 1 Кб) всех файлов, информация о которых выдана. Далее следуют строки с информацией об отдельных файлах. Первый символ в этих строках задает тип файла (d - каталог, минус означает обычный файл). Девять последующих символов отражают режим доступа к файлу: первые три символа - права доступа владельца файла, сле- дующие три - членов группы, последние три - права доступа про- чих пользователей. Наличие буквы r (чтение), w (запись) или x (выполнение) означает, что соответствующее право есть; знак ми- нус свидетельствует об отсутствии права. Например, файл /usr является каталогом, в который может писать только суперпользо- ватель, а читать и искать - все. Файл /unix - обычный, с таким же режимом доступа (это выполняемый файл, содержащий ядро опе- рационной системы). Следом идет число ссылок на файл. Для каталога оно заведомо не меньше 2 (ведь есть ссылки с именами . и ..). На файл /unix есть только одна ссылка. Следующие две колонки - имена владельца файла и группы, после чего идет размер файла в байтах. Отметим, что размер пустого каталога /mnt равен 32 байтам. Наконец, следуют дата и время последнего изменения и имя файла. Отметим, что имена файлов отсортированы в алфавитном порядке. Упомянем еще несколько употребительных опций команды ls(1): -R Рекурсивно обойти встретившиеся подкаталоги. -a Вывести список всех файлов (обычно не выводятся файлы, имена которых начинаются с точки). -d Если аргумент команды ls является каталогом, то выводить только его имя, а не содержимое. Часто используется с опцией -l для получения сведений о состоянии каталога. -x Вывод в несколько колонок с сортировкой по стро- кам. -t Имена файлов сортируются не по алфавиту, а по вре- мени (сначала идут самые свежие файлы). -r Изменить порядок сортировки на обратный алфавитный или, при наличии флага -t, сначала выводить более старые файлы. -b Выдавать непечатные символы, входящие в имя файла, в восьмеричном виде (\ddd). -i Выдавать в первой колонке номера описателей фай- лов. Приведем еще несколько примеров использования команды ls(1). По команде |ls -il /dev/console /dev/tty1 /dev/syscon /dev/systty будет выдана информация следующего вида: |151 crw--w--w- 4 root sys 0, 0 Oct 3 18:26 /dev/console |151 crw--w--w- 4 root sys 0, 0 Oct 3 18:26 /dev/syscon |151 crw--w--w- 4 root sys 0, 0 Oct 3 18:26 /dev/systty |151 crw--w--w- 4 root sys 0, 0 Oct 3 18:26 /dev/tty1 Как и предписывает опция -i - выданы номера описателей файлов. Мы видим, что для всех четырех имен они одинаковы (151), то есть эти имена ссылаются на один и тот же файл. Поскольку число ссылок равно четырем, то других ссылок на данный файл нет. Файл является символьным специальным. Для специальных файлов вместо размера выдаются так называемые старший и младший номера (в данном случае - 0, 0), однозначно определяющие соответствующее устройство. Опция -t позволяет увидеть в первую очередь файлы, которые из менялись позже других. Например, команда |ls -tl / выдает следующую инфромацию: |total 269 |drwxrwxrwx 2 sys sys 352 Oct 3 18:21 tmp |drwxr-xr-x 13 root sys 304 Oct 3 17:01 dss |drwxr-xr-x 30 root sys 480 Oct 3 15:30 usr |drwxr-xr-x 11 root sys 2080 Oct 1 20:35 etc |drwxr-xr-x 13 root sys 384 Oct 1 19:58 net |drwxr-xr-x 2 bin bin 1504 Sep 18 13:06 bin |drwxrwxr-x 22 root sys 384 Sep 14 15:10 udd |drwxr-xr-x 10 root sys 2608 Aug 22 19:13 dev |drwxr-xr-x 9 root sys 2160 Aug 31 15:10 util |-rwxr-xr-x 1 root sys 262438 Jun 26 09:20 unix |drwxr-xr-x 4 root sys 464 Jun 19 1989 lib |drwxrwxrwx 2 root sys 32 Jun 6 13:02 mnt |drwxr-xr-x 2 root sys 1024 Mar 20 1989 lost+found |drwxr-xr-x 2 root sys 128 Mar 13 1990 shlib Видеть, в первую очередь, самые свежие файлы полезно в тех слу- чаях, когда программная система перестала работать и нужно най ти причину поломки, а для этого требуется, в первую очередь, точно знать, что же, собственно, изменилось. В ОС UNIX в имя файла могут входить произвольные символы. Если в результате недопустимого редактирования командной строки (например, использования стрелок) в имя файла попали управляю- щие символы, выдача от команды ls может не соответствовать дей- ствительности. Чтобы сделать явными все скрытые символы в име- нах файлов, следует воспользоваться опцией -b. Чтобы получить информацию о числе свободных килобайтных блоков и незанятых описателей файлов в смонтированных файловых систе- мах, следует воспользоваться командой |df Результат работы этой команды может выглядеть следующим обра- зом: |/ (/dev/dsk/hd0s0 ): 7526 blocks 18096 i-nodes |/udd (/dev/dsk/hd0s1 ): 7648 blocks 20547 i-nodes На обеих смонтированных файловых системах осталось примерно по 7.5 Мб свободного пространства и около 20 тысяч свободных опи сателей файлов. Команда |du [каталог ...] выдает информацию о суммарном размере файлов, принадлежащих указанным каталогам и их подкаталогам. При отсутствии аргумен тов сообщаются сведения о текущем каталоге. Например, в ответ на команду |du /usr/guest будет выдано примерно следующее: |362 /usr/guest/BGS |1634 /usr/guest/test |2320 /usr/guest/GPP |22 /usr/guest/mt |522 /usr/guest/POLY |67 /usr/guest/lp |5252 /usr/guest Таким образом, каталог /usr/guest со всем своим содержимым за нимает более 5 Мб. 4.7.3. Создание и удаление файлов В ОС UNIX нет явной команды для создания обычных файлов. Как правило, файлы создаются сами, когда это необходимо, так что сама постановка задачи - создать файл "просто так" - является отчасти надуманной. В то же время, если файл создать все-таки нужно, полезно иметь в виду возможность переназначения вывода, которая имеется в языке shell (см. далее). Для создания каталогов служит команда |mkdir каталог ... С помощью одной команды можно создать несколько каталогов. В каждом из них появятся ссылки . и .., которые другими способами создать нельзя. Если нужно создать не один, а целую цепочку каталогов, следует воспользоваться опцией -p, например: |mkdir -p work/tmp/save По этой команде, в текущем каталоге, будет создан подкаталог work, в нем - каталог tmp, а уже в нем - каталог save. Для удаления обычных файлов (не каталогов) служит команда |rm файл ... Опишем три допустимые опции этой команды. Опция -i означает удаление файлов с запросом подтверждения. Например, возможен такой диалог с системой: |$ rm -i tmpfile |tmpfile: ? y |$ (символы, вводимые пользователем, выделены жирным шрифтом). Ес- ли в ответ на запрос системы ответить y, файл будет удален; в противном случае он останется. Вторая опция - -f. Она предписывает не выдавать диагностическо- го сообщения, если удаляемый файл не существует. Опция полезна, когда нет уверенности в существовании удаляемого файла и его отсутствие не является ошибкой. После выполнения команды |rm -f файл можно гарантировать, что файла нет (если, конечно, не возникает проблем с правами доступа). Наконец, "сверхмощная" опция -r позволяет удалять не только обычные файлы, но и каталоги со всем их содержимым (если, ко- нечно, хватает прав). Так, в процессе загрузки системы выполня- ется команда |rm -rf /tmp которая удаляет каталог /tmp и все содержащиеся в нем файлы и подкаталоги. Нечего и говорить о том, что пользоваться опцией -r следует крайне осторожно. Для удаления каталогов предпочти- тельнее использовать команду |rmdir каталог ... которая удалит каталог только в том случае, если он пуст. 4.7.4. Копирование и перемещение файлов. Создание новой ссылки на файл Команда копирования файлов cp(1) имеет следующий формат: |cp файл [файл ...] целевой_файл Если целевой_файл существует и является каталогом, то указанные файлы копируются в него под своими именами. Если целевой_файл является обычным (или не существует - тогда он создается как обычный), то заданный (один) файл копируется в него. Аналогичный синтаксис имеет команда перемещения файлов mv(1). Она отличается от команды копирования только тем, что файлы- оригиналы уничтожаются. Обычно команда mv используется для пе- реименования файлов и для копирования с транспортного флоппи- диска, чтобы не оставлять мусора на последнем, например |mv /mnt/myfile . Сходным образом записывается и команда создания новой ссылки на файл ln(1). Например, в процессе загрузки ОС UNIX выполняется команда |ln /dev/systty /dev/syscon которая порождает новую ссылку /dev/syscon на (специальный) файл, уже имеющий имя /dev/systty. Команда ln позволяет дать существующему файлу любое имя (в пределах одной файловой систе- мы), что бывает полезно, когда какая-либо программа обращается к нужному ей файлу по фиксированному имени. 4.7.5. Вывод содержимого файлов Для вывода содержимого файлов на экран терминала служит команда |cat файл ... Для просмотра больших файлов предпочтительнее пользоваться ко мандой |pg файл ... которая разбивает вывод на страницы и выдает их по явному ука- занию пользователя (например, по нажатию клавиши перевода стро- ки). Наконец, для просмотра нетекстовых файлов рекомендуется команда |hd файл Содержимое файла выводится в шестнадцатеричном и (если это воз- можно) в текстовом виде. 4.7.6. Смена владельца и режима доступа к файлу Для изменения владельца файла служит команда |chown владелец файл ... Владелец задается числовым идентификатором или входным именем. Изменить владельца может только нынешний владелец файла или су- перпользователь. Обычно приходится изменять владельца после пе реноса файлов с другого компьютера с другим соответствием чис- ловых идентификаторов и входных имен. Аналогичным образом меняется группа файла: |chgrp группа файл ... Чтобы изменить режим доступа к файлу, следует воспользоваться командой chmod(1): |chmod изменение_режима файл ... Как уже отмечалось, режим доступа определяет права для трех ка тегорий пользователей. При задании изменения_режима владелец файла обозначается буквой u, члены группы - буквой g, прочие пользователи - o. Добавлению прав соответствует знак +, удале- нию - знак -. После букв, обозначающих категорию пользователей, и знака операции следуют сами добавляемые (удаляемые) права - обычно r, w и/или x. Пусть, например, команда |ls -l myfile выдала следующую информацию: |-rw-rw-rw- 1 user sys 5601 Oct 3 10:40 myfile Чтобы отнять право на запись у членов группы и прочих пользова- телей и одновременно добавить себе право на выполнение, пользо- ватель user должен воспользоваться командой |chmod go-w,u+x myfile После этого команда |ls -l myfile выдаст |-rwxr--r-- 1 user sys 5601 Oct 3 10:40 myfile За счет рационального выбора режимов доступа можно сделать не- возможными большинство ошибочных операций с файлами (например, их удаление или изменение посторонними пользователями), не ог- раничивая, в то же время, свободы осмысленных действий. 4.7.7. Подсчет числа символов, слов и строк в файле Для подсчета числа символов, слов и строк в файлах служит ко- манда wc(1): |wc [-c] [-w] [-l] файл ... Опция -c предписывает подсчитывать символы, опция -w - слова, опция -l - строки. Например, по команде |wc -cl /usr/guest/test/tect1.for будет выдана такая информация: | 1247 69 /usr/guest/test/tect1.for Иными словами, в указанном файле 1247 символов, расположенных на 69 строках. Если не указывать опций, то будет подсчитываться все - и симво лы, и слова, и строки. Отметим, что для русских текстов, число слов подсчитывается неверно. 4.7.8. Поиск в файле заданного текста С помощью команды grep(1) можно отыскать строки файла, содержа- щие нужный текст. Команда grep записывается следующим образом: |grep [опция ...] текст файл ... Обычно текст - это просто цепочка символов, заключенная в ка- вычки. Что касается опций, упомянем четыре из них: -i При сопоставлении не различать большие и малые (латинские) буквы. -l Выдавать только имена файлов, в которых есть ус- пешно сопоставленные строки, разделяя имена пере- водами строк. -n Перед каждой выводимой строкой ставить ее номер в файле (строки нумеруются с 1). -v Выдавать только строки, не содержащие указанный текст. Например, если в файле /usr/guest/test/tect1.for нужно найти все строки, содержащие вызовы подпрограмм, можно воспользовать- ся командой |grep -i "call" /usr/guest/test/tect1.for В ответ будет выдано | call INVAL(M,N,A) | 3 call LAPL(M,N,A,B,ERR) | call MAP(M,N,A,10) | call INVAL(M,N,B) На самом деле, возможности команды grep(1) значительно шире. Можно порекомендовать внимательно изучить соответствующую статью Справочника пользователя. 5. ПРОЦЕССЫ Каждый процесс в ОС UNIX однозначно характеризуется своим чис- ловым идентификатором. Другими атрибутами процесса (но уже не уникальными) являются идентификатор пользователя, запустившего процесс, идентификатор родительского процесса и имя терминала, с которого процесс запущен. 5.1. Выдача информации о процессах Для выдачи информации о процессах служит команда ps(1). По умолчанию информация выдается только о процессах, ассоциирован- ных с данным терминалом. Выводятся идентификатор процесса, идентификатор терминала, истраченное к данному моменту время центрального процессора (ЦП) и имя команды. Например, выдача команды |ps может выглядеть так: |PID TTY TIME COMMAND | 94 tty2 0:02 sh |145 tty2 0:00 sh |154 tty2 2:45 rk.20.01 |356 tty2 0:00 prconecm |357 tty2 0:00 sh |358 tty2 0:00 ps Если нужна более подробная информация, следует пользоваться оп- циями. Перечислим наиболее употребительные из них: -e Вывести информацию обо всех процессах (а не только о процессах, ассоциированных с данным терминалом). -l Выдать подробную информацию о процессах [аналог опции -l команды ls(1)]. -t список_терминалов Выдавать информацию только о процессах, ассоцииро- ванных с терминалами из заданного списка_термина- лов. Терминал - это либо имя файла-устройства, например ttyномер или console, либо просто номер, если имя файла начинается с tty. Элементы списка должны разделяться запятыми. По команде |ps -l выдается информация следующего вида: | F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME COMD |10 S 108 94 1 0 30 20 50728 37 506e4 tty2 0:02 sh |10 S 108 145 94 0 30 20 50c38 39 50bf4 tty2 0:00 sh |10 S 108 154 145 30 30 20 50cc8 885 50c84 tty2 3:19 rk.20.01 |10 S 108 426 154 6 30 20 51268 15 51224 tty2 0:00 prconecm |10 S 108 427 426 5 30 20 512f8 37 512b4 tty2 0:00 sh |10 O 108 428 427 12 66 20 51388 29 tty2 0:00 ps Колонка UID содержит числовой идентификатор владельца процесса (то есть пользователя, запустившего процесс), колонка PPID - идентификатор родительского процесса. Вообще говоря, процессы ОС UNIX образуют древовидную структуру, в которой у одного п цесса может быть несколько преемников (сыновей). Смысл осталь ных колонок описан в статье ps(1) Справочника пользователя. 5.2. Уничтожение процессов Процессу можно послать сигнал, если известен его (процесса) идентификатор. Для этого служит команда |kill [-номер_сигнала] идентификатор_процесса ... Как правило, команда kill используется для уничтожения процес- сов (отсюда и ее название) без указания посылаемого сигнала, например |kill 154 В таком случае, процессу посылается, так называемый сигнал за- вершения (с номером 15), который процесс, в принципе, может проигнорировать. Чтобы уничтожить процесс наверняка, исключив возможность перехвата или игнорирования сигнала, следует посы- лать сигнал с номером 9, например |kill -9 145 Разумеется, обычный пользователь не может послать сигнал чужому процессу. 5.3. Измерение времени работы процессов Чтобы измерить время, которое требуется для выполнения некото- рой команды, следует пользоваться конструкцией вида |time команда Указанная команда выполняется, после чего выводятся астрономи ческое время ее работы, время ЦП и накладные расходы системы. Например, командная строка |time /usr/guest/test/gdouble вызовет появление на экране информации следующего вида: | Конец итераций; log(2) = 0.693137 | |real 9:38.8 |user 6:51.6 |sys 22.3 Команда time(1) - удобное средство измерения времени выполнения процессов без вмешательства в их работу. 5.4. Стандартный ввод, стандартный вывод, стандартный протокол Как правило, с процессом ассоциированы по крайней мере три фай- ла - стандартный ввод, стандартный вывод, стандартный протокол. Обычно стандартный ввод назначен на клавиатуру терминала, а стандартный вывод и стандартный протокол - на экран. Со стан- дартного ввода читаются команды и (иногда) исходные данные для них (см. следующий абзац). На стандартный вывод поступают ре- зультаты выполнения команд. В стандартный протокол помещаются диагностические сообщения. Большинство команд, аргументами которых должны быть файлы, чи- тают информацию со стандартного ввода, если файлы не заданы. Таковы команды cat(1), grep(1), pg(1), wc(1). Обычно подобная возможность используется, когда команды вызываются в составе конвейера (см. следующий раздел). Если же стандартный ввод наз- начен на клавиатуру, то в качестве признака конца файла исполь- зуется комбинация клавиш CTRL+D . В ОС UNIX процессы обращаются к файлам посредством дескрипто- ров, в роли которых выступают небольшие целые числа. Число 0 обозначает стандартный ввод, 1 - стандартный вывод, 2 - стан- дартный протокол. 6. ТЕРМИНАЛ Пользователи ОС UNIX взаимодействуют с системой посредством терминалов. На клавиатуре пользователь набирает запрос, ответ на который система выдает на экран. Чтобы узнать имя специаль- ного файла, соответствующего конкретному терминалу, следует набрать на этом терминале команду |tty В ответ может быть выдано |/dev/tty5 Каждый терминал обладает рядом характеристик, которые можно оп- росить и/или изменить. Для этого служит команда stty(1), имею- щая следующий формат: |stty [-a] [-g] [характеристика ...] Будучи вызванной без опций, эта команда выдает значения основ ных характеристик. Смысл опций таков: -a Выдать значение всех установленных характеристик. -g Выдать текущие установки в формате, который может быть использован в качестве аргумента другой ко- манды stty. Например, в ответ на команду |stty может быть выдано: |speed 9600 baud; -parity |intr = ^c; quit = ^b; erase = DEL; kill = ^u; swtch = ^g; |brkint -inpck icrnl -ixany onlcr onlret tab3 |echo echoe echok echonl Разъясним смысл выдачи. Данный терминал обменивается с компь- ютером информацией со скоростью 9600 бод, то есть 9600 бит/сек. При этом не производится контроль четности. Далее, если нажать клавишу CTRL+C, то процесс, запущенный с терминала, получит сигнал прерывания, что скорее всего приведет к его (процесса) аварийному завершению. Если нажать CTRL+B, то процесс не только аварийно завершится, но и оставит свой образ памяти в файле с именем core. Укажем еще, что клавиша DEL отменяет последний набранный символ, то есть действует как забой, а клавиша CTRL+U отменяет всю строку. Установленная характеристика echo предпи- сывает отображать на экране символы, вводимые с клавиатуры. Смысл остальных характеристик описан в статье stty(1). Чтобы переустановить какую-либо характеристику, следует после команды stty указать имя характеристики и ее новое значение. Например, после выполнения команды |stty kill '^k' для отмены строки придется нажимать CTRL+K. Если выполнить строку |stty -echo на экране перестанут отображаться символы, вводимые пользовате лем, что, правда, не повлияет на выдачу результатов работы ко- манд. Подобный режим применяется для обеспечения секретности, например, во время ввода пароля. Для восстановления эхоотобра- жения можно воспользоваться строкой |stty echo Каждый терминал относится к определенному типу. У разных типов терминалов разные возможности и системы команд. В ОС UNIX име ется общий механизм, с помощью которого экранные утилиты (нап- ример, редакторы) настраиваются на конкретный тип терминала. В основе этого механизма - база данных terminfo(4), содержащая описания более тысячи типов и модификаций терминалов. Для опре- деления типа конкретного терминала ОС UNIX использует значение переменной окружения TERM (см. следующий раздел). 7. ЯЗЫК SHELL В дальнейшем изложении слово shell будет употребляться в двух смыслах - как имя языка программирования и как название интерп- ретатора. После того как пользователь вошел в систему, он начинает взаи- модействовать с командным интерпретатором. Обычно в качестве такого интерпретатора выступает программа /bin/sh, известная под именем shell (оболочка). Командный интерпретатор не являет ся частью ядра операционной системы и не обладает какими-либо особыми привилегиями в смысле доступа к системным ресурсам. Ничто не мешает пользователю написать свой интерпретатор. На станции БЕСТА доступны несколько интерпретаторов [упомянем C-shell (программа /bin/csh) и V-shell (программа /usr/binb/ vsh)]. Пожалуй, shell - худший из них. Во-первых, он поддержи- вает только строчный (а не экранный) интерфейс. Во-вторых, воз можности редактирования командной строки по существу сводятся к использованию клавиши забоя. В-третьих, не поддерживается про- токол сеанса работы и нельзя вводить новые команды, использу ранее набранные строки в качестве заготовок. Почему же в данной публикации рассматривается именно язык shell? Причин тому две. Первая состоит в том, что на станции БЕСТА рекомендуется рабо- тать в рамках Интегрированной Среды Разработки Программ (ИСРП), которая компенсирует два последних из перечисленных недостатков shell'а. Вторая причина, пожалуй, более основательна. Дело в том, что все системные действия, выполняемые при включении и выключении компьютера, при установке новых пакетов программ и т.п. запрограммированы на языке shell. Естественно, их прихо- дится изменять с учетом потребностей конкретной группы пользо вателей станции БЕСТА. А чтобы вносить изменения в программу, желательно разбираться в языке, на котором она написана. 7.1. Определения Под пробелом в дальнейшем понимается не только собственно про- бел, но также и символ табуляции. Имя - это последовательность букв, цифр, символов подчеркива- ния, начинающаяся с буквы или подчеркивания. Параметр - это имя, цифра или любой из символов *, @, #, ?, -, $, !. Простая команда - это последовательность слов, разделенных про- белами. Первое слово определяет имя команды, которая будет вы- полняться; оставшиеся слова, за исключением описанных ниже слу чаев, передаются команде в качестве аргументов. Имя команды пе- редается как аргумент 0 [см. exec(2)]. Значение простой команды - это ее код завершения, если она выполнилась нормально, или (128 + код ошибки), если ненормально [см. также signal(2)]. Команда - это либо простая команда, либо одна из управляющих конструкций (см. далее). Кодом завершения команды является код завершения последней выполненной простой команды. Конвейер - это последовательность команд, разделенных знаком |. При этом стандартный вывод всех команд, кроме последней, нап- равляется посредством системного вызова pipe(2) на стандартный ввод следующей команды конвейера. Каждая команда выполняется как самостоятельный процесс; shell ожидает завершения последней команды. Ее код завершения становится кодом завершения конвейе- ра. Формально будем считать, что простая команда является част ным случаем конвейера. Список - это последовательность одного или нескольких конвей- еров, разделенных символами ;, &, && или || и, быть может, за- канчивающаяся символом ; или &. Из четырех указанных операций ; и & имеют равные приоритеты, меньшие, чем у && и ||. Приоритеты последних также равны между собой. Символ ; означает, что кон вейеры будут выполняться последовательно, а & - параллельно (то есть shell не ожидает завершения конвейера). Операция && (||) означает, что список, следующий за ней, будет выполняться лишь в том случае, если код завершения предыдущего конвейера нулевой (ненулевой). В списке в качестве разделителя конвейеров вместо символа ; можно использовать символ перевода строки. Командная строка - это строка текста на языке shell. Shell-процедура - это файл, содержащий программу на языке shell. 7.2. Общий механизм выполнения команд Для выполнения (почти) каждой простой команды shell порождает отдельный процесс. В рамках этого процесса выполняется програм ма, хранящаяся в файле, заданном именем команды. Программа мо жет быть выполняемой, то есть содержать машинные инструкции, или же она может быть shell-процедурой, то есть содержать текст на языке shell. В первом случае программа интерпретируется ап паратно, с участием ядра операционной системы. Во втором случае программу интерпретирует shell. Внешне отличия двух видов прог- рамм проявляются только в скорости выполнения и в том, что shell-процедуры не нуждаются в компиляции и редактировании свя зей (интерпретируется сам исходный текст). Файл, содержащий программу, может храниться как в системном ка- талоге, так и в личном каталоге пользователя и быть продуктом деятельности последнего. У файла может быть произвольное имя. Тем самым набор команд языка shell является расширяемым - его пополняет каждая новая программа, написанная пользователем. Строго говоря, пополняет набор команд даже ссылка с новым име- нем на уже существующий файл. 7.3. Примеры конвейеров Конвейер - одна из самых красивых конструкций ОС UNIX. Идея его проста, но на редкость продуктивна. С помощью конвейеров удает- ся комбинировать возможности, предоставляемые разными команда- ми, получая по существу новое качество. Например, команда ls(1) не подсчитывает число файлов в катало- ге, а лишь выдает информацию о них. С другой стороны, команда wc(1) способна подсчитать число строк в файле, но не имеет от ношения к распечатке содержимого каталогов. Если же построить конвейер из двух упомянутых команд, легко подсчитать число фай лов в каталоге. Например, результатом работы конвейера |ls -a /usr/guest/test | wc -l будет число 103 [напомним, что команда wc(1), вызванная без ар гументов, подсчитывает число строк в файле стандартного ввода, который в данном случае является результатом работы команды ls(1)]. Значит, в каталоге /usr/guest/test 103 файла, если счи- тать и элементы, соответствующие текущему и вышележащему ката- логам. Еще один пример. Пусть нужно выдать информацию о файлах текуще- го каталога, которые модифицировались в октябре. К цели ведет конвейер |ls -al | grep "Oct " Команда grep играет здесь роль фильтра, который пропускает для вывода только часть строк, выдаваемых ls. Можно выстроить и трехступенчатый конвейер, если требуется подсчитать число файлов, модифицированных в октябре: |ls -al | grep "Oct " | wc -l Здесь команду grep с еще большим правом можно назвать фильтром. Приведем еще один пример конвейера, когда нужно просмотреть подробную информацию о большом каталоге: |ls -Rl /dev | pg Связующее звено между последовательными компонентами конвейера называется каналом. Иными словами, для интерпретации конвейера shell создает временный файл типа "канал", в который с одного конца информацию пишут, а с другого конца - читают. С помощью команды tee(1) можно организовать ответвление канала, то есть помещать информацию не только на стандартный вывод, но и в ука- занные файлы: |tee [-a] файл ... Опция -a предписывает добавлять информацию в файлы, а не пере- писывать их с начала. Например, если нужно не только подсчитать число файлов из теку- щего каталога, модифицированных в октябре, но и поместить ин- формацию о них в файл для последующего анализа, следует постро- ить четырехступенчатый конвейер: |ls -al | grep "Oct " | tee /tmp/tmpinf | wc -l В результате выполнения этого конвейера на экране появится чис- ло нужных файлов, а в файле /tmp/tmpinf - информация о них. 7.4. Примеры простейших shell-процедур Даже простейшие shell-процедуры дают возможность избежать ввод длинных строк с трудновоспроизводимым содержанием. Например, поместив текст |# Монтирование флоппи-диска на каталог /mnt | |/etc/mount /dev/dsk/fd /mnt в файл по имени flon, можно в дальнейшем монтировать флоппи- диски, набирая просто |flon Попутно отметим, что слово, начинающееся символом #, и все пос ледующие слова вплоть до перевода строки игнорируются, то есть могут служить комментариями. Несколько более сложный пример - процедура для форматирования флоппи-диска и создания на нем пустой файловой системы: |# Инициализация флоппи-диска | |/etc/format /dev/rdsk/fd |/etc/mkfs /dev/dsk/fd 800 1 5 |/etc/labelit /dev/dsk/fd mnt floppy Если приведенный текст хранится в файле formatflop, то для ини- циализации флоппи-диска достаточно ввести это имя, а не запоми- нать тройку чисел 800, 1, 5. 7.5. Переменные и аргументы shell-процедур Переменные обозначаются именами. Значения могут присваиваться им привычным способом, то есть посредством команд вида: |имя=значение [имя=значение] ... Все значения в языке shell трактуются как текстовые. Подчерк нем, что конструкция |имя=значение должна быть одним словом в смысле shell'а, то есть в ней не мо- жет быть пробелов. Обычно в языках программирования ясно из контекста, где имеется в виду имя переменной, а где значение. Так, в левой части опе- ратора присваивания обычно используется имя, в правой - значе- ние. В языке shell это не так. Для обозначения перехода от име- ни переменной к значению используется явная операция $. Если в команде встречается конструкция |$имя то вместо нее интерпретатор shell подставляет значение перемен- ной с указанным именем. Допускается и запись |${имя} с тем же смыслом, если нужно отделить имя от последующего текс- та. Рассмотрим пример. После выполнения команд |a=value_of_variable |b=1+2 |echo a = $a |echo b = $b [команда echo (эхо) выдает на стандартный вывод свои аргумен- ты] на экране появится: |a = value_of_variable |b = 1+2 Значения формальных аргументов shell-процедур обозначаются как |$цифра $0 есть имя интерпретируемой shell-процедуры. Если фактических аргументов, заданных при вызове команды, меньше чем 9, "лишние" формальные аргументы получают пустые значения. О том, как доб- раться до фактических аргументов с номерами большими, чем 9, будет сказано ниже (см. управляющую конструкцию for и команду shift). В качестве примера рассмотрим shell-процедуру, которая выдает на стандартный вывод свое имя и значения трех первых аргумен- тов. Имя команды: $0 |echo Значение первого аргумента: $1 |echo Значение второго аргумента: $2 |echo Значение третьего аргумента: $3 Пусть приведенный текст помещен в файл с именем three_args. Тогда в результате выполнения команды |three_args arg1 . - arg4 на экране появится: |Имя команды: three_args |Значение первого аргумента: arg1 |Значение второго аргумента: . |Значение третьего аргумента: - Поскольку в тексте shell-процедуры упомянуты только первые 3 аргумента, значения аргументов с большими номерами (даже если они заданы, как в приведенном примере) не влияет на ее работу. Команда |three_args arg1 -- выдаст: |Имя команды: three_args |Значение первого аргумента: arg1 |Значение второго аргумента: -- |Значение третьего аргумента: Значение третьего формального аргумента пусто. Прежде чем начнется выполнение командной строки, то есть будет вызвана заданная в ней команда, строка обрабатывается shell'ом, который выполняет в ней некоторые подстановки. С одной из таких подстановок - значения переменной вместо конструкции $имя - мы уже познакомились. Язык shell содержит ряд аналогичных конст- рукций. Рассмотрим одну из них. Там, где в командной строке встречается запись вида |${имя:-слово} вместо нее подставляется значение переменной с указанным име- нем, если это значение непусто, в противном случае подставляет- ся слово. Например, если в shell-процедуре встретилось присваи- вание |initdir=${1:-/} то переменная initdir получит значение первого аргумента, если оно непусто. Если же процедуру вызвали без аргументов, значени- ем initdir станет символ /. Подобные конструкции - удобный спо- соб задания подразумеваемых значений. 7.6. Служебные переменные shell'а Значения некоторых переменных устанавливаются самим shell'ом. Перечислим эти переменные и опишем их предназначение. # Количество фактических аргументов (десятичное). - Флаги, указанные при запуске shell'а или посредст- вом команды set (см. далее). ? Десятичное значение, возвращенное предыдущей син- хронно выполненной командой. $ Идентификатор процесса, в рамках которого выполня ется shell. ! Идентификатор последнего асинхронно запущенного процесса. *, @ Совокупность всех фактических аргументов (начиная с $1), разделенных пробелами. Напомним: чтобы получить значения этих переменных, перед ними нужно поставить знак $. Между значениями $@ и $* есть некоторые тонкие различия, на ко- торых мы останавливаться не будем. Несколько усложним процедуру three_args, чтобы продемонстриро- вать только что описанные возможности. |echo Идентификатор текущего процесса: $$ |echo Имя команды: $0 |echo Число фактических аргументов: $# |echo Совокупность всех аргументов: $@ |echo Значение первого аргумента: $1 |echo Значение второго аргумента: $2 |echo Значение третьего аргумента: $3 Если теперь выполнить командную строку |three_args arg1 . - arg4 на экране появится примерно следующее: |Идентификатор текущего процесса: 168 |Имя команды: three_args |Число фактических аргументов: 4 |Совокупность всех аргументов: arg1 . - arg4 |Значение первого аргумента: arg1 |Значение второго аргумента: . |Значение третьего аргумента: - 7.7. Окружение процессов Окружение - это набор пар (имя, значение), который передается выполняемой программе так же, как и обычный список аргументов. Иными словами, порождаемые процессы наследуют окружение процес- са-предка. Компонентами окружения являются, помимо прочих, сле- дующие переменные и их значения: HOME Подразумеваемый аргумент команды cd(1) - основ- ной каталог пользователя. PATH Список имен каталогов для поиска команд. В дальнейшем подобные списки называются списками поиска. Элементы списка разделяются двоеточием. Пустой элемент означает текущий каталог. PS1 Основное приглашение shell'а (по умолчанию "$ "). TERM Тип пользовательского терминала. TZ Информация о часовом поясе. Чтобы выдать информацию об окружении на экран, следует восполь- зоваться командой |env Поясним смысл переменных PATH, TZ и TERM. Прежде чем выполнить команду, shell ищет файл с соответствующим именем в последовательности каталогов, являющейся значением пе- ременной PATH. Естественно назвать подобную последовательность списком поиска. Если, например, значение $PATH суть |:/net/bin:/bin:/usr/bin:/util:/dss/rk:/usr/binb то нужный файл будет сначала разыскиваться в текущем каталоге, затем в каталоге /net/bin и т.д. Как только файл будет найден, поиск прекратится. Это важно, если в разных каталогах есть од- ноименные выполняемые файлы. Так, в каталогах /net/bin и /bin есть программа с именем cp. Поскольку /net/bin стоит в списке поиска раньше, именно оттуда и будет взят файл cp. Переменная TZ задает локальный часовой пояс. Первые три символа суть имя часового пояса, следующие - разница между всемирным и локальным временем. Например, значение |MDT-3 описывает часовой пояс Москвы. Разница с всемирным временем составляет 3 часа. Переменная TERM хранит тип терминала пользователя. Интерактив- ные утилиты (например, редакторы) с помощью значения $TERM и базы данных о терминалах terminfo(4) настраиваются на конкрет ный тип терминала. Если Вам сменили терминал, не забудьте соот- ветственно изменить значение переменной окружения TERM. Для изменения окружения мало присвоить новое значение соот- ветствующей переменной. Дело в том, что по умолчанию переменные считаются локальными по отношению к shell-процедуре, то есть присваивание изменит локальную переменную, но не затронет одно- именную переменную окружения. В результате в окружение новых процессов (порожденных, например, для выполнения последующих команд данной shell-процедуры) войдет переменная со старым зна- чением. Чтобы лучше уяснить ситуацию, рассмотрим пример. Пусть есть две shell-процедуры - proc1 и proc2: |# Процедура proc1 | |TZ=MEZ-1 |echo Из proc1: $TZ |proc2 |# Процедура proc2 | |echo Из proc2: $TZ В результате выполнения процедуры proc1 на экране появится: |Из proc1: MEZ-1 |Из proc2: MDT-3 то есть порожденный процесс унаследовал стандартное значение переменной окружения TZ. С помощью конструкции |export имя переменная с указанным именем помещается в окружение, то есть становится глобальной. Например, shell-процедура /etc/addprofi- le, которая выполняется как составная часть процесса входа пользователя в систему, содержит следующие строки: |export PATH |PATH=:/net/bin${PATH}:/util:/dss/rk:/usr/binb Первая строка вызывает отождествление глобальной и локальной переменной PATH, вторая - добавляет в начало списка поиска те- кущий каталог и каталог /net/bin, а в конец - каталоги /util, /dss/rk и /usr/binb. Измененное значение $PATH становится ком- понентом окружения и будет унаследовано порождаемыми процесса- ми. Вернемся к процедуре proc1 и добавим в нее команду export: |# Процедура proc1 | |export TZ |TZ=MEZ-1 |echo Из proc1: $TZ |proc2 Теперь в результате выполнения процедуры proc1 на экране поя- вится: |Из proc1: MEZ-1 |Из proc2: MEZ-1 Мы видим, что окружение изменилось. 7.8. Подстановка результатов выполнения команд Если в командной строке встретилась цепочка символов, заключен- ная в обратные кавычки (`), эта цепочка интерпретируется как команда, стандартный вывод которой подставляется вместо упомя нутой конструкции. Говорят, что в этом случае производится подстановка результатов выполнения команды, а сами обратные ка- вычки называют символами подстановки. Опишем несколько употребительных способов использования подста- новки результатов. Пусть файл filelist содержит список имен других файлов, над совокупностью которых требуется проделать некоторое действие. Если в командную строку поместить конструк- цию |... `cat filelist` ... то это все равно, что явно указать в командной строке все файлы из списка. Пример: |ls -l `cat filelist` Нет нужды в том, чтобы каждая команда умела читать свои аргу- менты из файла: имеются универсальный механизм подстановки ре- зультатов и команда cat. В языке shell все значения считаются текстовыми. Значит, для выполнения операций с числами нужны особые средства. Команда expr(1) рассматривает свои аргументы как компоненты выражения и выдает результат вычисления этого выражения на стандартный вы- вод. Например, после выполнения строки |i=`expr $i + 1` значение переменной i увеличится на 1. Подчеркнем, что каждый компонент выражения должен быть записан как отдельное слово, то есть отделяться от других компонентов пробелами. Не забудьте о символе $, если нужно обратиться к значению переменной; помните и о том, что вокруг символа = пробелов быть не должно. 7.9. Управляющие конструкции Среди прочих, язык shell содержит следующие управляющие конст- рукции: |for имя [in слово ...] | do список |done При каждой итерации переменная имя принимает сле- дующее значение из набора in слово ... . Если конструкция in слово ... опущена, то список выпол- няется для каждого формального аргумента. |if список_1 | then список_2 | [elif список_3 | then список_4] | ... | [else список_5] |fi Выполняется список_1 и если код его завершения 0, то выполняется список_2, иначе - список_3 и если код его завершения 0, то выполняется список_4 и т.д. Если же коды завершения всех списков, исполь- зованных в качестве условий, оказались ненулевыми, выполняется else-часть (список_5). Если else-часть отсутствует, и ни одна then-часть не выполнялась, возвращается нулевой код завершения. |while список_1 | do список_2 Пока код завершения последней команды списка_1 есть 0, выполняются команды списка_2. При замене служебного слова while на until условие продолже ния цикла меняется на противоположное. Если коман- ды из списка_2 не выполнялись вообще, код заверше- ния устанавливается равным нулю. |case слово in | [шаблон [| шаблон] ...) список ;;] |esac Выполняется список, соответствующий первому из шаблонов, успешно сопоставленных со словом. Формат шаблона аналогичен используемому для генераци имен файлов (см. далее). Приведем примеры управляющих конструкций. Сначала усовершенст- вуем процедуру three_args, чтобы она выдавала значения всех, а не только первых трех аргументов: |echo Идентификатор текущего процесса: $$ |echo Имя команды: $0 |echo Число фактических аргументов: $# |echo Совокупность всех аргументов: $@ |i=1 |for arg |do | echo Значение аргумента номер ${i}: $arg | i=`expr $i + 1` |done В конструкциях if и while часто используется команда test(1), проверяющая некоторое условие и вырабатывающая нулевой или не- нулевой код завершения в зависимости от того, оказалось ли ус- ловие соответственно истинным или ложным. Команду можно записы- вать любым из двух способов: |test условие или употребив пару квадратных скобок: |[ условие ] Условие может состоять из следующих примитивов: -r файл Истина, если файл существует и доступен для чте- ния. -w файл Истина, если файл существует и доступен для запи- си. -x файл Истина, если файл существует и является выполняе- мым. -f файл Истина, если файл существует и является обычным файлом. -d файл Истина, если файл существует и является каталогом. -c файл Истина, если файл существует и является специаль- ным символьным файлом. -b файл Истина, если файл существует и является специаль- ным блочным файлом. -p файл Истина, если файл существует и является именован- ным каналом. -s файл Истина, если файл существует и имеет ненулевой размер. s1 = s2 Истина, если цепочки символов s1 и s2 равны. s1 != s2 Истина, если цепочки символов s1 и s2 не равны. s1 Истина, если s1 - непустая цепочка символов. n1 -eq n2 на, если целые числа n1 и n2 алгебраически равны. На месте -eq могут быть также операции сравнения -ne (не равно), -gt (больше), -ge (боль- ше или равно), -lt (меньше), -le (меньше или рав- но). Примитивы могут комбинироваться с помощью круглых скобок а так- же следующих операций (в порядке уменьшения приоритета): ! Унарная операция отрицания. -a Логическое И. -o Логическое ИЛИ. Как и в случае команды expr, каждый компонент условия должен быть окружен пробелами. Приведем пример использования конструкции if. Файл /etc/rc2, который запускается в процессе загрузки системы, содержит сле- дующие строки: |if [ -s ${f} ] |then | /bin/sh ${f} start |fi Если файл, имя которого является значением переменной f, су ществует и имеет ненулевой размер, он выполняется с аргументом start. Приведем теперь пример использования конструкции case. Файл /etc/addprofile, который выполняется при входе каждого пользо- вателя в систему, содержит строки, аналогичные следующим: |case $TERM in | d460* ) | if [ -r D460_LOAD ] | then | stty -echo -echoe -echok -echonl | cat D460_LOAD; echo "\036N\036FS45\036O"; | stty echo echoe echok echonl | fi | ;; | d211 ) | echo "\036FU1" | ;; |esac Если значение переменной окружения TERM начинается на d460 и если файл D460_LOAD существует и доступен на чтение, выполняет- ся загрузка шрифтов из этого файла. Если терминал суть d211, он переводится в восьмибитный режим (посылкой управляющей последо- вательности), чтобы нормально отображать русские буквы. 7.10. Генерация имен файлов После всех подстановок, прежде чем команда начнет выполняться, в каждом составляющем ее слове ищутся символы *, ?, и [. Если находится хотя бы один из них, то это слово рассматривается как шаблон имен файлов и заменяется именами файлов, удовлетворяющих данному шаблону. Файлы подставляются в алфавитном порядке. Если ни одно имя файла не удовлетворяет шаблону, слово остается не- изменным. Символ . в начале имени файла или непосредственно после /, так же как и сам символ /, должны быть заданы в шабло- не явно. Трактовка символов *, ? и [: * Сопоставляется с произвольной цепочкой символов, в том числе с пустой. ? Сопоставляется с произвольным символом. [...] Сопоставляется с любым из перечисленных в скобках символов. Пара символов, разделенных знаком -, обозначает отрезок алфавита, включающий сами ука занные символы. Если сразу, вслед за [ идет !, шаблону удовлетворяет любой символ, не перечислен ный в скобках. Рассмотрим несколько примеров. Чтобы подсчитать суммарное число строк во всех фортрановских файлах текущего каталога, достаточ- но выполнить команду |wc -l *.for В качестве второго примера приведем фрагмент файла /etc/rc2: |for f in /etc/rc2.d/S* |do | if [ -s ${f} ] | then | /bin/sh ${f} start | fi |done В цикле будут в алфавитном порядке запускаться все непустые файлы из каталога /etc/rc2.d, имена которых начинаются на S. Рассмотрим команду |rm -f .*.[Bb]? Она удалит из текущего каталога все файлы, имена которых начи- наются с точки, а сразу после второй точки стоит одна из букв - B или b, а затем произвольный символ. Читателю предлагается самостоятельно ответить на вопрос, удалит ли команда |rm -f *.[Bb][AaUu] файл с именем .bu. Наконец, рассмотрим довольно сложный пример. Требуется так пе- реименовать фортрановские файлы текущего каталога, чтобы окон- чание .f заменилось на .for. В ОС UNIX есть команда |basename цепочка_символов [суффикс] которая убирает из цепочки_символов любой префикс, оканчиваю- щийся на /, и суффикс (если он есть) и выдает результат на стандартный вывод. Применим ее для решения сформулированной за- дачи. |for f in *.f |do | mv $f `basename $f .f`.for |done Особенностью приведенного примера является использование подс- тановки результатов команды как части слова (в данном случае - как части нового имени файла). 7.11. Переназначение ввода/вывода Перед тем как команда будет выполнена, ее ввод и вывод могут быть переназначены, для чего используется специальная нотация, интерпретируемая shell'ом. Описанные ниже конструкции могут располагаться в любом месте простой команды, могут предшество вать команде или завершать ее и не передаются в качестве аргу- ментов команды. <слово Использовать файл слово для стандартного ввода (дескриптор файла 0). >слово Использовать файл слово для стандартного вывода (дескриптор файла 1). Если файла нет, он создает- ся; если есть, он опустошается. >>слово Использовать файл слово для стандартного вывода. Если файл существует, то выводимая информация до бавляется в конец (то есть сначала производится поиск конца файла); в противном случае файл созда- ется. Если любой из этих конструкций предшествует цифра, она опреде- ляет дескриптор (вместо подразумеваемых дескрипторов 0 или 1), который будет ассоциирован с файлом, указанным в конструкции. Например, строка |... 2>protocol переназначает стандартный протокол (дескриптор 2) в файл по имени protocol. Чтобы переназначить стандартный протокол туда же, куда уже наз- начен стандартный вывод, следует употребить конструкцию |... 2>&1 Приведем два примера. Пусть нужно измерить время выполнения не- которой команды, направив ее результаты в файл cmd.res, а дан- ные о времени - в файл cmd.time. К цели ведет строка |time команда >cmd.res 2>cmd.time Второй пример. В shell-процедуре /etc/mksys, которая инициали зирует только что собранный компьютер, имеется цикл: |i=0 |while [ $i -lt 40 ] |do | >lost+found/g$i | i=`expr $i + 1` |done |rm lost+found/* С его помощью создается 40 файлов в каталоге lost+found, кото- рые затем удаляются. Отметим, что здесь переназначается стан- дартный вывод пустой команды, в результате чего создается пус той файл. Примечание Поясним смысл приведенного фрагмента. При проверке и коррекции файловой системы утилитой fsck(1M) в каталог /lost+found помещаются непустые файлы, на которые нет ссылок. Сложность в том, что пока утилита fsck работа- ет, ни один файл не должен расширяться, то есть в ката- логе /lost+found должны быть заранее заготовленные, пустые места. 7.12. Экранирование Под экранированием будем понимать защиту символов от интерпре- тации shell'ом. Следующие символы трактуются shell'ом по-особо- му; если эти символы не экранированы, они завершают предшеству- ющее им слово: |; & ( ) | ^ < > пробел табуляция перевод_строки Символы *, ?, [, ] также играют для shell'а особую роль, однако разделителями слов на являются. Каждый из перечисленных выше символов может быть экранирован, то есть представлять самого себя, если перед ним стоит \ или он расположен между кавычками ('' или ""). Как всегда, приведем несколько примеров. Пусть нужно умножить значение переменной i на 5. К цели ведет строка |i=`expr $i \* 5` Если звездочку не экранировать, shell подставит вместо нее име- на файлов текущего каталога, не начинающиеся со звездочки. В результате выражение, являющееся аргументом команды expr, ско- рее всего станет синтаксически некорректным. Второй пример. Пусть нужно выдать информацию о всех файлах т кущего каталога, которые модифицировались последний раз 3 ок тября. Конвейер |ls -al | grep "Oct 3" сделает то, что нужно. Кавычки использованы для экранирования двух пробелов в разыскиваемой цепочке символов. Без них команда grep попыталась бы найти текст Oct в файле с цифровым именем 3. 7.13. Специальные команды shell'а Как уже отмечалось, подявляющее большинство команд выполняется в рамках порожденных процессов. Нетрудно видеть, однако, что для некоторых команд должно быть сделано исключение. Рассмот- рим, например, команду |cd каталог Если для ее выполнения будет порожден процесс, смена каталога случится именно в нем; для текущего процесса ничего не изменит- ся. Таким образом, сам shell должен распознавать и выполнять неко- торые команды в рамках текущего процесса. Подобные команды бу дем называть специальными или собственными. Перечислим некото рые из них. |. файл Shell читает и выполняет команды из файла, затем возобновляется чтение со стандартного ввода; при поиске файла используется значение переменной PATH. Иными словами, специальная команда . позво- ляет выполнить любую команду в рамках текущего процесса. |cd [каталог] Сделать текущим заданный каталог. Если каталог не указан, используется значение переменной HOME. |echo [аргумент ...] Выдать аргументы на стандартный вывод, разделяя их пробелами [см. также echo(1)]. |eval [аргумент ...] Выполнить команду, заданную аргументами eval. |exec [аргумент ...] Сменить программу процесса: в рамках текущего про цесса команда, заданная аргументами exec, заменяет shell. В качестве аргументов могут быть указаны спецификации ввода/вывода и, если нет никаких дру- гих аргументов, будет лишь переназначен ввод/вывод текущего shell'а. |exit [код_завершения] Завершить выполнение shell'а с указанным кодом. При отсутствии аргумента, код завершения определя- ется последней выполненной командой. Чтение симво- ла конца файла, также, приводит к завершению shell'а. pwd Выводит имя текущего каталога. [см. pwd(1)]. |read [переменная ...] Со стандартного ввода читается одна строка и де- лится на слова; первое слово присваивается первой переменной, второе - второй и т.д., причем все ос- тавшиеся слова присваиваются последней переменной. Исходная строка имеет продолжение, если в конце ее стоит последовательность \перевод_строки. Символы, отличные от перевода строки, также могут быть эк- ранированы с помощью \, который удаляется перед присваиванием слов. Возвращается нулевой код за- вершения, если только не встретился конец файла. |shift [n] Формальные аргументы, начиная с (n+1)-го, переиме- новываются в $1 и т.д. По умолчанию n=1. test Вычислить условное выражение [см. test(1)]. |type [имя ...] Для каждого имени выдается, как оно будет интерп- ретироваться при использовании в качестве имени команды. |ulimit [размер_в_блоках] Установить максимальный размер_в_блоках (по 1 Кб) тех файлов, в которые пишут данный shell и его по томки (читать можно файлы любого размера) [см. ulimit(1)]. Если размер не указан, выдается теку щий лимит. Каждый пользователь может уменьшить собственный лимит, но только суперпользователь мо- жет его увеличить. Некоторые пояснения. С помощью команды exec можно сменить прог- рамму текущего процесса. Например, если пользователь привык р ботать в C-shell'е, то он может перейти туда по команде |exec csh При этом обычный shell бесследно исчезнет. Команда read позволяет читать информацию со стандартного ввода и разбивать ее на слова. Например, shell-процедура formatflop содержит следующие строки: |echo 'Enter names of file system and volume: \c' |read fsn vn |/etc/labelit /dev/dsk/fd $fsn $vn Обратим внимание, что здесь одинарные кавычки экранируют не только пробелы, но и символ \. Если пользователь дал своей программе имя test, выполнить ее в рамках shell'а ему не удастся - будет работать специальная ко- манда test. Это одна из ловушек shell'а, о которой необходимо знать. Команда type позволяет узнать, как shell будет интерпретировать заданное имя. Например, команда |type test выдаст: |test is a shell builtin Результатом выполнения строки |type cat будет |cat is /bin/cat то есть для выполнения команды cat будет использован файл /bin/cat. Если кажется, что команда работает непонятным образом, следует применить type для выяснения того, что же собственно выполняет- ся. В системе UNIX имеется ограничение на максимальный размер фай- ла, который может записать пользовательский процесс. Команда ulimit позволяет опросить или изменить этот лимит. Отметим, что в данном случае, права обычных пользователей трактуются shell'ом несколько односторонне - лимит можно только уменьшить. Важную роль играет еще одна специальная команда - set. Она ис- пользуется для изменения режима работы shell'а и для присваива- ния новых значений формальным аргументам. Сразу же отметим, что наивное присваивание |цифра=слово трактуется shell'ом как запуск программы с именем цифра=слово, то есть оно не позволяет изменить значение формального аргумен- та. Команда set записывается в виде |set [опция ...] [аргумент ...] Из опций упомянем только одну: -x Выводить команды и их аргументы непосредственно перед выполнением. Иными словами, после выполнения команды |set -x будет производиться трассировка текущей shell-процедуры. Чтобы прекратить трассировку, нужно воспользоваться командой |set +x Если в команде set заданы аргументы, они станут новыми значени- ями $1, $2 и т.д. Рассмотрим фрагмент shell-процедуры /etc/rc2, которая выполняется в процессе загрузки системы: |set `who -r` |if [ $9 = "S" ] | . . . Команда who -r выдаст строку следующего вида: | . run-level 2 Oct 17 09:56 2 0 S Слова из этой строки станут аргументами команды set. В резуль- тате значением $1 станет точка, значением $2 - слово run-lelel, ..., значением $9 - S, так что проверяемое условие окажется ис- тинным. 7.14. Резюме Shell - мощный язык программирования. Обратим внимание на имею- щиеся в нем возможности по комбинированию команд с помощью кон- вейеров, на подстановки значений переменных и результатов вы- полнения команд, на генерацию имен файлов по шаблонам. 8. НЕКОТОРЫЕ ПОЛЕЗНЫЕ КОМАНДЫ В данном разделе описываются команды для поиска файлов, а также для обмена информацией со стримерной лентой и с флоппи-дисками MS-DOS. 8.1. Поиск файлов Команда |find список_поиска выражение рекурсивно просматривает каждый из каталогов, перечисленных в списке_поиска, отыскивая файлы, удовлетворяющие логическому вы ражению, построенному с помощью описанных ниже средств. В спи- сок_поиска могут входить и обычные файлы. Элементы списка_по ка разделяются пробелами. Далее n обозначает целое десятичное число, на месте которого могут также указываться комбинации +n, что означает "больше, чем n", и -n, что означает "меньше, чем n". Перечислим некоторые элементарные логические выражения и их результаты: -name шаблон_файлов Истина, если текущий файл удовлетворяет шаблону_- файлов. Символы шаблона, имеющие для shell'а спе- циальный смысл, должны быть экранированы. -type c Истина, если файл имеет тип c, где c есть b, c, d, p или f - блочный или символьный специальный файл, каталог, именованный канал или обычный файл. -size n[c] Истина, если файл занимает n блоков (по 512 байт). Если указана буква c, то размер файла задается в символах. Напомним, что с помощью комбинаций +n и -n можно проверять размер (и три указанные ниже характеристики) не только на равенство, но и на неравенство. -atime n Истина, если последний доступ к файлу производился n дней назад. Сама команда find изменяет время доступа к каталогам, входящим в список_поиска. -mtime n Истина, если файл последний раз модифицировался n дней назад. -ctime n Истина, если характеристики файла (размер, режим доступа) последний раз изменялись n дней назад. -exec команда Истина, если после выполнения команды возвращается нулевой код завершения. Запись команды должна за- канчиваться экранированной точкой с запятой. Аргу- мент команды, заданный в виде пары фигурных скобок { }, заменяется текущим маршрутным именем файла. -ok команда Эквивалентно -exec за исключением того, что перед выполнением команды запрашивается подтверждение (в виде сгенерированной командной строки со знаком вопроса в конце), и она выполняется только при от- вете y. -print Всегда истина; вызывает выдачу маршрутного имени текущего файла на стандартный вывод. -newer файл Истина, если текущий файл был модифицирован позд- нее указанного файла. ( выражение ) Истина, если истинно заключенное в скобки выраже- ние (скобки должны быть экранированы от интерпре- тации shell'ом). Элементарные логические выражения могут комбинироваться с по мощью следующих операций (в порядке уменьшения приоритета): Унарная операция отрицания, обозначается !. Логическое И, обозначается пробелом. Логическое ИЛИ, обозначается -o. Приведем несколько примеров. Пусть нужно подсчитать число ФОРТ- РАНовских файлов в текущем каталоге и его подкаталогах. Вос- пользуемся конвейером: |find . -name \*.for -print | wc -l Обратим внимание на то, что команда find - одна из немногих, интерпретирующая шаблоны имен файлов самостоятельно. Собствен но, у нее нет другого выхода, поскольку она должна рекурсивно обойти указанные каталоги и в каждом из них искать файлы, имена которых удовлетворяют заданному шаблону. Нетрудно видеть, что стандартный shell-механизм генерации имен файлов в данном слу чае не годится. Не следует забывать об экранировании символов, имеющих для shell'а специальный смысл, так как в противном слу- чае команда find заведомо не выдаст нужный результат. Не следу- ет забывать также об "условии" -print, поскольку, иначе, find просто ничего не выдаст (хотя и обойдет все подкаталоги и отбе- рет нужные файлы). Рассмотрим более сложный пример. Пусть нужно подсчитать суммар- ное число строк во всех фортрановских файлах текущего каталога и его подкаталогов. Решений может быть несколько, рассмотрим три из них. Во-первых, можно организовать конвейер: |cat `find . -name \*.for -print` | wc -l Команда find отберет имена нужных файлов, cat выдаст их сово- купное содержимое на стандартный вывод, а команда wc подсчитает общее число строк. По существу ту же идею можно выразить в дру- гой форме: |find . -name \*.for -exec cat {} \; | wc -l Здесь содержимое нужных файлов будет выдаваться на стандартный вывод по мере их обнаружения. Наконец, можно поступить совсем просто, сделав нужные файлы ар- гументами команды wc: |wc -l `find . -name \*.for -print` Правда, при этом будет выдаваться еще и число строк в каждом из фортрановских файлов. Напишем теперь команду, позволяющую удалить из текущего катало- га и его подкаталогов все файлы нулевого размера, а также объ- ектные файлы, к которым не было доступа более месяца, запраши- вая подтверждение: |find . \( -size 0c -o -name \*.o -atime +30 \) -ok rm {} \; Обратим внимание на пробелы, окружающие экранированные скобки и экранированную точку с запятой. 8.2. Преобразование файлов в архивный формат Команда cpio(1) используется для архивизации и извлечения, а также для копирования файлов. Одна из трех основных опций - -o, -i или -p - должна быть задана обязательно; она и определяет характер работы cpio. Команда |cpio -oB (архивизация) читает со стандартного ввода список маршрутных имен (по одному в строке) и копирует эти файлы на стандартный вывод вместе с маршрутными именами и информацией о файлах. Оп- ция -B предписывает записывать информацию блоками по 5120 байт. Команда |cpio -i [шаблон ...] (извлечение) выделяет отдельные файлы из стандартного ввода, который, как предполагается, является результатом работы cpio -o. Извлекаются только файлы, имена которых соответствуют хотя бы одному из указанных шаблонов, построенных по принятым в shell'е правилам для генерации имен файлов. Символу / могут со- ответствовать в шаблоне метасимволы ?, *, и [...]. Может быть указано несколько шаблонов, а если не указано ни одного, то по умолчанию шаблоном будет *, то есть будут извлечены все файлы. Команда |cpio -p каталог (копирование) читает со стандартного ввода список маршрутных имен (по одному в строке) и, в соответствии с опциями командной строки, копирует заданные файлы в дерево каталогов с указанным корневым каталогом. Укажем еще несколько полезных опций команды cpio: -d Создавать каталоги в случае необходимости. -t Вывести оглавление архива, ранее созданного с по- мощью команды cpio. Никакие файлы не создаются. -u Безусловно заменять существующий файл архивным с тем же именем (обычно старый файл не заменяет файл, изменявшийся позднее). -v Вывести список имен обработанных файлов. Если ис- пользована опция -t, то оглавление выглядит как вывод команды ls -l [см. ls(1)]. -l Везде, где это возможно, не копировать файлы, а создавать ссылки. Эта опция употребляется только с опцией -p. -m Сохранять прежнее время последней модификации (то есть то время, которое указано в заголовке файла). При отсутствии этой опции время последней модифи- кации устанавливается равным текущему времени. -f Извлекать все файлы, кроме тех, имена которых со- ответствуют шаблонам. Эта опция употребляется только с опцией -i. Рассмотрим пример - копирование на флоппи-диск содержимого те кущего каталога и его подкаталогов. |flon |find . -print | cpio -pdlmv /mnt |floff 8.3. Обмен информацией со стримерной лентой Команда |dd [опция=значение ...] копирует указанный входной файл в указанный выходной файл. Сре- ди прочих допускаются следующие пары опция=значение: if=файл Задается имя входного файла; по умолчанию исполь зуется стандартный ввод. of=файл Задается имя выходного файла; по умолчанию исполь- зуется стандартный вывод. bs=n Устанавливается размер порций, которыми произво дится копирование; по умолчанию размер равен 1 Кб. Команда dd(1) особенно часто используется в сочетании с cpio(1) для сохранения файлов на стримерной ленте и для восстановления их с ленты. Например, чтобы сохранить на ленте содержимое теку- щего каталога и всех его подкаталогов, можно применить следую- щий трехступенчатый конвейер: |find . -print | cpio -oBmv | dd of=/dev/mt bs=5k Информация будет записываться на ленту порциями по 5 Кб. Для восстановления с ленты содержимого текущего каталога и всех его подкаталогов достаточно двухступенчатого конвейера: |dd if=/dev/mt | cpio -idmvu Похожий конвейер годится, если нужно ознакомиться с содержимым ленты: |dd if=/dev/mt | cpio -itv Упомянем еще о команде vsplit(1M), которая позволяет расщепить выходной поток на несколько томов или, наоборот, "слить" инфор мацию с нескольких носителей. 8.4. Удобные команды для работы с лентой Команды find(1), cpio(1) dd(1) и vsplit(1M) образуют нижний уровень работы с ленточными архивами. Имеются, однако, и более удобные средства. Команда |copall каталог ... сохранит на стримерной ленте содержимое указанных каталогов (разумеется, со всеми подкаталогами) в формате cpio. Выполнение команды |restall приведет к восстановлению информации, ранее сохраненной коман- дой copall. По команде |restall -t будет выдана информация о содержимом ленты (в формате cpio -itv). Команды copall и restall реализованы как shell-процедуры. Наде- емся, что читатель и пользователь станции БЕСТА легко в них разберется. Подробно эти команды описаны в статьях copall(1M) и restall(1M) Справочника администратора. 8.5. Работа с флоппи-диском MS-DOS Аппаратное и программное обеспечение рабочей станции БЕСТА поз- воляет читать/писать флоппи-диски с файловой структурой MS-DOS (емкостью 360 Кб). Обычно для этой цели используется команда ccp, обеспечивающая копирование файлов с перекодировкой. Син- таксис команды ccp почти такой же, как у cp(1): |ccp [опция ...] файл [файл ...] целевой_файл Все, что было сказано о команде cp, применимо к ccp. Отметим лишь, что к флоппи-диску MS-DOS нужно обращаться как к каталогу /dos. Подчеркнем, что такой диск не нужно монтировать, доста- точно вставить его в дисковод. Соответственно, по окончании ра- боты следует просто вынуть флоппи-диск. Каталог /dos не должен существовать в смысле ОС UNIX - команда ccp трактует это имя особым образом, направляя информацию на флоппи-диск MS-DOS. Опция -v приводит к выдаче в стандарный протокол имен копируе- мых файлов и так называемого "градусника" из минусов, отражаю щего состояние процесса копирования. Как только в стандартном протоколе появится 80 минусов (минусы заполнят строку на экране терминала до конца), пересылка очередного файла завершится. Известно, что существует несколько кодировок русских букв. Оп- ции команды ccp определяют способ их перекодировки во время ко- пирования (если опции не заданы, выполняется копирование без перекодировки): -a Преобразовать из кодировки Бесты в альтернативную кодировку. -A Преобразовать из альтернативной кодировки в коди- ровку Бесты. -r Преобразовать из кодировки Бесты в RSCII. -R Преобразовать из RSCII в кодировку Бесты. Примечание Поскольку названия различных кодировок не являются об- щепринятыми, ниже приводятся соответствующие кодовые таблицы. |Беста| 0 1 2 3 4 5 6 7 8 9 A B C D E F -A | 0 1 2 3 4 5 6 7 8 9 A B C D E F |-----+-------------------------------- ---+-------------------------------- | 0 | 0 | | 1 | 1 | | 2 | ! " # $ % & ' ( ) * + , - . / 2 | ! " # $ % & ' ( ) * + , - . / | 3 | 0 1 2 3 4 5 6 7 8 9 : ; < = > ? 3 | 0 1 2 3 4 5 6 7 8 9 : ; < = > ? | 4 | @ A B C D E F G H I J K L M N O 4 | @ A B C D E F G H I J K L M N O | 5 | P Q R S T U V W X Y Z [ \ ] ^ _ 5 | P Q R S T U V W X Y Z [ \ ] ^ _ | 6 | ` a b c d e f g h i j k l m n o 6 | ` a b c d e f g h i j k l m n o | 7 | p q r s t u v w x y z { | } ~ 7 | p q r s t u v w x y z { | } ~ | 8 | 8 | А Б В Г Д Е Ж З И Й К Л М Н О П | 9 | 9 | Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я | A | Ъ ъ A | а б в г д е ж з и й к л м н о п | B | B | | | | | | + + + | C | Ю А Б Ц Д Е Ф Г Х И Й К Л М Н О C | + + + + - + + + + + + + - + + | D | П Я Р С Т У Ж В Ь Ы З Ш Э Щ Ч D | + + + + + | E | ю а б ц д е ф г х и й к л м н о E | р с т у ф х ц ч ш щ ъ ы ь э ю я | F | п я р с т у ж в ь ы з ш э щ ч F | | -R | 0 1 2 3 4 5 6 7 8 9 A B C D E F | ----+-------------------------------- | 0 | | 1 | | 2 | ! " # $ % & ' ( ) * + , - . / | 3 | 0 1 2 3 4 5 6 7 8 9 : ; < = > ? | 4 | @ A B C D E F G H I J K L M N O | 5 | P Q R S T U V W X Y Z [ \ ] ^ _ | 6 | Ю А Б Ц Д Е Ф Г Х И Й К Л М Н О | 7 | П Я Р С Т У Ж В Ь Ы З Ш Э Щ Ч Ъ | 8 | + + + + + | + + - | + | 9 | | A | | B | | C | ` a b c d e f g h i j k l m n o | D | p q r s t u v w x y z { | } ~ - | E | ю а б ц д е ф г х и й к л м н о | F | п я р с т у ж в ь ы з ш э щ ч ъ Как всегда, приведем несколько примеров. Сначала запишем файл на флоппи-диск MS-DOS с преобразованием в альтернативную коди- ровку: |ccp -av myfile /dos Теперь выполним обратную перепись с флоппи-диска в каталог /tmp: |ccp -Av /dos/myfile /tmp Копирование без перекодировки с ведением протокола: |ccp -v *.o /tmp Отметим еще одну особенность команды ccp. Если в качестве файла задан символ -, происходит чтение со стандартного ввода. Если символ - задан в качестве целевого_файла, выполняется запись на стандартный вывод; в этом случае может быть задано несколько исходных файлов. Таким образом, команда ccp может использовать- ся как элемент конвейера. Приведем пример, когда несколько фай- лов сливаются в один и затем записываются на флоппи-диск MS- DOS: |ccp -av *.c - | ccp - /dos 9. РЕЗЮМЕ В предыдущих разделах рассмотрены основы ОС UNIX с точки зрения пользователя. При этом были упомянуты далеко не все команды. Цель состояла в другом - дать общее представление о системе, о ее основных механизмах. Знакомясь с новой системой, важно проникнуться ее философией. Одна из основных посылок ОС UNIX - многократное использование ранее разработанных программ. Если Вы имеете общее представле- ние о спектре команд ОС UNIX и умеете пользоваться такими мощ- ными средствами, как язык shell, механизм конвейеров и т.п., Вы сможете быстро решить многие из стоящих перед Вами задач, не вникая в тонкости традиционного программирования.