Приемы профессиональной работы в UNIX

             

АНАЛИЗ ПРИМЕРА ФАЙЛА НАСТРОЙКИ СИСТЕМЫ


Файл .profile, как следует из его названия (профилирование - формирование контура, очертаний), функционирует для установки и инициализации параметров системы, которые вам нужны. Сюда входит установка терминалов, определение переменных, запуск программ и конфигурирование исполняющей системы. Пример файла настройки можно найти в описании команды profile(4). Рассмотрим .profile, используемый автором. Мы включили его на столь ранней стадии, чтобы предложить вам коснуться понятий, которые более подробно раскрываются далее в этой книге. Не заботьтесь о понимании работы каждой части примера. Пока что просто сделайте мысленную отметку возможностей. Ваш .profile может быть проще и почти наверняка будет другим.

1 # @(#).profile v1.0 Defines "home" on the system Author: Russ Sage 3 CHOICE="ushort" 4 case $CHOICE in 5 ufull) PS1="`uuname -l`> ";; 6 ushort) PS1="`uuname -l|cut -c1-3`> ";; 7 graphic) PS1="^[[12mj^[[10m ";; 8 esac 10 LOGNAME=`logname` 11 HOME=`grep "^$LOGNAME:" /etc/passwd | cut -d: -f6` 12 MAIL=/usr/spool/mail/$LOGNAME 13 export LOGNAME HOME MAIL

15 HA=$HOME/adm 16 HBB=$HOME/bbs 17 HB=$HOME/bin 18 HD=$HOME/doc 19 HE=$HOME/etc 20 HM=$HOME/mail 21 HP=$HOME/proj 22 HSR=$HOME/src 23 HSY=$HOME/sys 24 HT=$HOME/tmp 25 HDIRS="HA HBB HB HD HE HM HP HSR HSY HT" 26 export $HDIRS HDIRS

28 P=/usr/spool/uucppublic/$LOGNAME; export P

30 CDPATH=.:..:$HOME:$HDIRS 31 PATH=.:/bin/:/usr/bin:/etc:$HOME/bin 32 SHELL=`grep "^$LOGNAME:" /etc/passwd|cut -d: -f7` 33 export CDPATH PATH SHELL

35 case "`basename \`tty\``" in 36 console) eval `tset -m ansi:ansi -m :\?ansi -r -s -Q`;; 37 tty00) eval `tset -m ansi:ansi -m :\?ansi -r -s -Q`;; 38 tty01) eval `tset -m ansi:ansi -m :\?ansi -r -s -Q`;; 38 esac

41 echo TERM = $TERM 42 TERMCAP=/etc/termcap 43 export TERM TERMCAP

45 HZ=20 46 TZ=PST8PDT 47 export HZ TZ

49 umask 0022

51 echo "\nTime of this login : `date`" 52 lastlog -l

54 RED="^[[31m" 55 GREEN="^[[32m" 56 YELLOW="^[[33m" 57 BLUE="^[[34m" 58 CYAN="^[[35m"

60 case "`date|cut -d' ' -f1`" in 61 Mon) echo "$RED";; 62 Tue) echo "$GREEN";; 63 Wed) echo "$YELLOW";; 64 Thu) echo "$BLUE";; 65 Fri) echo "$CYAN";; 66 esac



ЧТО ТАКОЕ СОСЕДСТВО?


Во многих более старых мини- и микрокомпьютерах среда имеет "плоскую" файловую систему. Это значит, что все файлы размещаются в одной огромной области хранения и нет логических разделов для их разграничения. Отсутствие разделов порождает массу файлов, через которые нужно пробраться, когда вы хотите найти определенный элемент. Некоторые системы имели в своих файловых системах групповые разделы, но обычно такие разделы были различными плоскими файловыми системами. Время показало, что такой тип среды (или модели) - не лучшее решение. Решение, которое использует UNIX,- перевернутая модель дерева. Корень системы находится наверху, а ветви растут в стороны и вниз. Имеется один и только один корень наверху. Ветви могут исходить в любом направлении и простираться вниз на любую глубину. Кроме того, вы можете иметь присоединяемые ветви, которые можно изъять из системы, а затем вернуть обратно. Они монтируются на существующую в системе древовидную структуру.

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



ФАЙЛЫ 4.2 BSD




Первым файлом здесь является .cshrc. Это первая стадия настройки системы на пользователя, выполняемой интерпретатором cshell. В системе UNIX присутствие "rc" в имени файла означает "команды запуска" ("run commands") или "запуск при загрузке" ("run on boot up").

Файл .login является синонимом файла .profile интерпретатора sh. Этот файл содержит команды настройки на среду пользователя, которая вам нужна при регистрации в системе.

Следующий файл - .logout. Он выполняется, когда вы выходите из системы. Например, вы можете применить его для печати учетной информации, такой как время, в течение которого вы работали в системе, используемый вами размер дискового пространства и т.д. System V не имеет подобного файла.

Следующий файл - .msgsrc, предназначенный для команды msgs(1) системы Berkeley. Файл .msgsrc содержит последний, прочитанный вами файл сообщений. Файлы сообщений хранятся в виде последовательно пронумерованных файлов в каталоге /usr/msgs.



ФАЙЛЫ System V


Первый файл - это .news_time. Дата этого файла соответствует тому, когда вы последний раз читали новости в каталоге /usr/news. Для чтения новостей пользуйтесь командой news(1). Эта команда выдает новости, появившиеся позже даты создания файла .news_time.

Следующий файл - .profile. Этот файл выполняется при каждой регистрации в интерпретаторе shell и может быть использован для привязки вашей собственной среды. В дальнейшем мы рассмотрим этот файл более подробно.

Следующий файл - calendar (календарь). Этот файл содержит даты и сообщения. Команда calendar(1) читает в этом файле даты, очень близкие к текущей дате. Затем печатаются или посылаются вам по почте сообщения.

Последний файл - mbox, ваш системный почтовый ящик. Когда вы с помощью команды mail(1) сохраняете почту, она направляется по умолчанию в mbox.



ФАЙЛЫ В РЕГИСТРАЦИОННОМ КАТАЛОГЕ


Файлы, описываемые ниже, разделяются на три категории: файлы, которые обычно присутствуют в вашей системе, если вы работаете в System V, файлы, которые имеются обычно в Berkeley 4.2, и файлы, которые создаются при использовании программ из настоящей книги.



КАК РАБОТАЕТ .profile


Когда вы входите в систему, регистрационная программа выполняет интерпретатор shell с параметром '-' (например, -sh). Это сигнализирует интерпретатору shell, что сейчас момент регистрации и что должен быть выполнен файл настройки. Сначала выполняется /etc/profile - общий файл настройки, установленный системным администратором для всех пользователей, а затем файл .profile пользователя. Каждый интерпретатор shell после этого больше не запускает эти установочные программы. В файле /etc/ profile интересно проверить машинно-зависимую информацию и посмотреть, какие умолчания были для вас установлены. Если вы хотите выполнить ваш .profile в любой момент после входа в систему, наберите ". .profile" (можно писать и ".profile", проверено, что обе формы работают - Прим. переводчика).

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

При использовании переменные shell являются локальными для работающего в данный момент интерпретатора shell. Их можно передать интерпретаторам shell более глубокого уровня путем их "экспортирования". Следовательно, если вы создаете новый командный процессор, все ваши экспортированные переменные будут по-прежнему определены для этого интерпретатора shell. Исчерпывающий список переменных shell, установленных по умолчанию и используемых системой, см. в приложении 1. Отметим, что в нашем примере файла настройки для каждого подкаталога первого уровня, который есть в нашем регистрационном каталоге, мы также имеем переменные shell, связанные с именем этого подкаталога. Таким образом, мы можем легко обращаться к различным областям нашего регистрационного каталога.



КАТАЛОГИ


Первым каталогом является adm. Он содержит административные файлы, которые вы можете иметь, например расписания, информацию о сотрудниках, встречах и т.д.

В каталоге bbs имеются подкаталоги для каждой "доски объявлений", которую вы вызываете. Когда вы обращаетесь к этим системам, вы имеете место для размещения всех соответствующих файлов и данных. Необходимая вам информация - это меню для системы, вспомогательный текст, загрузки программ и общая информация, которая вас интересует.

Каталог bin содержит все инструментальные средства, которые у вас есть. Это могут быть командные файлы или объектные модули откомпилированных программ. Подкаталог src не обязателен. В нем хранится исходный код на языке Си для объектных модулей, имеющихся в bin, так что исходный текст для быстрой фиксации ошибок и изменения всегда под рукой.

Каталог doc - это корень всех видов документации. Подкаталогами здесь могут быть формы, письма, записки, разнообразная информация и отчеты. Каждый подкаталог содержит определенные файлы в этих областях. Каталог etc содержит любые системные или административные команды и файлы, которыми вы пользуетесь. Если вы имеете административные обязанности, типичным содержимым этого каталога может быть резервная копия текущих конфигурационных файлов, используемых системой. Вы можете сделать резервную копию файлов

/.profile /etc/bcheckrc brc checklist gettydefs group inittab motd mountable unmountable passwd profile rc /usr/lib/crontab /usr/lib/uucp/L.sys USERFILE uudemon.day uudemon.hr uudemon.wk

или любой другой информации о системе.

Каталог proj предназначен для специальных проектов, которые у вас есть. Скорее всего, вы назовете этот каталог не proj, а по имени проекта, например, dev для разработки (development) или qa для чистовой шлифовки (quality assurance). Все данные, корреспонденция, документация и исходный код для каждой работы направляются в главный каталог проекта. Конечно, у вас может быть более одного каталога проекта.

Следующий каталог - mail. Это хорошее место для размещения вашей почтовой корреспонденции от других людей, использующих систему. Имена файлов в этом каталоге являются пользовательскими. Например, если бы я получил почту от Боба, то она находилась бы в файле с именем bob.


Каталог src - для всего исходного кода. Логически сгруппируйте ваш исходный код по подкаталогам, чтобы облегчить его поиск в будущем. Возможными подкаталогами являются asm для ассемблерного кода, c для исходного кода на Си, games (игры), misc (разное), script для командных файлов и sys для любого исходного кода, относящегося к системе. (Если вы держите исходные тексты ваших личных инструментов в каталоге /bin/src, то здесь вы, возможно, продублируете их.)

Каталог sys - это склад информации, имеющей отношение к системе. Здесь могут быть резервные копии критических системных файлов, документация по областям системы, куски выводимой информации команд who, ps, uucp, регистрационных файлов или что-либо иное.

Последний каталог - tmp, который является рабочей областью для размещения временных файлов. В основном все, что находится в tmp, вы можете в любое время удалить, и средство can, описанное в главе 3, помогает вам в этом.

Отметим, что регистрационный каталог имеет минимальное количество обычных файлов. Это уменьшает путаницу, которая может происходить с плоскими файловыми системами. Каждый файл должен быть на своем месте, но может быть размещен не только здесь. Если возникает какой-либо род задач, когда файлы, связанные с этой задачей, могут быть перепутаны с другими файлами, создайте отдельный каталог.


"МНОГООБРАЗИЕ СРЕД"


Каждая компьютерная система поддерживает много различных сред. Эти среды используются как строительные блоки для создания функциональных рабочих систем. Различные уровни необходимы как для сокращения объема работы по управлению машиной, так и для построения такого интерфейса, чтобы мы могли использовать компьютер на относительно высоком, удобном для человека уровне.

Мы рассматриваем эту модель, так как она помогает выстроить в ряд уровни, на которых мы можем работать. Имея больше знаний о том, где мы находимся в системе, и о том, как она функционирует вокруг нас, мы можем легче строить растущие абстрактные модели на вершине тех моделей, которые уже имеются. Компьютеры - это фактически рабочие модели абстракций, так что чем больше мы понимаем модели, тем лучше мы можем использовать их для упрощения и ускорения нашей работы.

Многообразие моделей на рис.1-1 . демонстрирует различные уровни, функционирующие внутри компьютера. Нижний слой - это стартовая точка, от которой многообразие растет вверх. Каждый уровень строится на предыдущем и используется для поддержки уровня, расположенного над ним. Для каждого более высокого уровня среда более объемна и более "виртуальна" в том смысле, что имеет место меньше условных ограничений. Верхние уровни используют для своей работы нижние и, таким образом, скрывают подробности, необходимые для работы этих нижних уровней. Мы можем создать модели высокого уровня, которые работают на машине более низкого уровня, не зная ничего о нижних уровнях.

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

Рис. 1-1 Многообразие компьютерных сред

--------------------------------------------------------------------------- \ L7 / Командные файлы (scripts) \________________________________/ \ L6 / Прикладные программы, \____________________________/ интерпретатор команд, языковые генераторы \ L5 / Компилятор \________________________/ \ L4 / Операционная система \____________________/ \ L3 / Ядро \________________/ \ L2 / Условная машина, ассемблер \____________/ \ L1 / Микропрограммы \________/ \ L0 / Логические схемы, аппаратные средства \____/ ---------------------------------------------------------------------------



ОБЩАЯ СИСТЕМНАЯ СРЕДА


Системная среда не просто НАХОДИТСЯ в системе UNIX, а ЯВЛЯЕТСЯ системой UNIX. Как мы увидим в этой книге, вся система - UNIX, Си, команды, файлы и т.д. - это просто логический подход к функционированию компьютера. Программное обеспечение - это то, что определяет система для конечного пользователя. Мы можем представлять все машины, работающие в системе UNIX, как одинаковые и трактовать каждый UNIX как один и тот же. Мы предполагаем, что реакция машины будет каждый раз одинаковой.

Мы можем смотреть на UNIX таким же образом, как на физические законы. Мы ограничены ими, но мы также вольны применять эти законы в ситуациях и областях, с которыми мы до этого никогда не встречались. Мы можем доверять этим законам и допускать, что они применимы везде, куда бы мы ни направились. Такова система UNIX, по крайней мере в идеале. Система имеет много сред. Важно понимать, что они собой представляют, как взаимодействуют и для чего могут быть использованы. Так же, как

программы = структуры данных + алгоритмы

так и

UNIX = файловое дерево + утилиты

Среда UNIX - это сочетание двух важнейших вещей: файлового дерева и интерфейса системных вызовов. Это дерево допускает бесконечное расширение возможностей, позволяя монтировать внешние дисковые области в любой точке файловой системы. Дерево помогает также в сборе логически связанных файлов, что делает систему более организованной. Интерфейс системных вызовов обеспечивает набор инструментов, из которых можно построить большинство других функций. Определение интерфейса System V имеется в виде типографской книги и может быть найдено в книжных магазинах. Строгое следование этому стандарту гарантирует совместимость с постоянно развивающейся AT&T System V.



ОБЩЕЕ ФАЙЛОВОЕ ДЕРЕВО


Для того чтобы лучше понять мир UNIX, посмотрите пример распечатки структуры UNIX на рис.1-3 . Это наглядное представление полного дерева корневой файловой системы. Любые другие расширения файловой системы монтируются на эту файловую систему. Точкой временного монтирования является /mnt. Более постоянные точки монтирования должны быть созданы администратором, например /0, /1 и т.д. или /usr1, /usr2 и т.д.



ПЕРВЫЙ СЛОЙ


Самым левым каталогом является /bin, который содержит все главные двоичные утилиты. Это наибольший из двух основных каталогов двоичных модулей.

Следующий каталог - /dev, в котором размещены все файлы уст- ройств. Файлы устройств являются точками доступа к периферии, подсое- диненной к системе. Этот файл привязан к периферии с помощью ядра и драйвера устройства.

Административные утилиты и конфигурационные файлы хранятся в /etc. Примерами являются getty и gettydef, init и inittab, а также файл паролей (/etc/passwd).

Следующий каталог - /lib, где размещены библиотеки компилятора.

Здесь могут храниться и другие типы библиотек.

Каталог /lost+found используется утилитой fsck (главное средство поддержания файловой системы) для хранения логически удаленных файлов. Если на самом деле вы хотите сохранить эти файлы, они могут быть изв- лечены из этой удерживающей области после завершения уборки файловой системы.

Следующий каталог - /mnt. Это временная точка монтирования для файловых систем. Мы часто монтируем и демонтируем файловые системы просто для того, чтобы запустить быструю проверку чего-либо. Здесь подходящее место для этого.

Главным временным рабочим каталогом системы является /tmp. Многие утилиты, такие как vi, fsck, интерпретаторы shell и программы резервного копирования, используют /tmp для хранения рабочих файлов.

Следующий каталог - /usr, который применяется как точка монтирования. Файловая система, смонтированная здесь, содержит дополнительную системную информацию и каталоги пользователей. Это разделение между загружаемой файловой системой и пользовательской файловой системой было сделано, чтобы сбалансировать загрузку диска. Если бы все важные файлы были в одном разделе, он был бы слишком большим. Производительность может быть ухудшена, если все действия направлены в одну логическую область диска. Благодаря разбивке всей системы на две, каждая файловая система поддерживает разумное количество свободного пространства. Чуть ниже мы рассмотрим каталог /usr более подробно.

Последний файл - это само ядро, /unix. Весь /unix фактически существует и представляет собой большой a.out (скомпилированный объектный файл). Ядро изготавливается путем запуска ld на группе библиотек, которые загружаются по очереди в огромный исполняемый модуль, называемый /unix. Машина запускается с первых 512 байтов корневой файловой системы. Программа начальной загрузки, которая находится здесь, загружает программу загрузки большего размера, иногда называемую /boot. /boot загружает и запускает /unix.



ПЛАНИРОВКА РЕГИСТРАЦИОННОГО КАТАЛОГА


Как только ваш регистрационный каталог присоединен к определенному месту дерева, вы получаете полное управление структурой, которая существует ниже этого места. Вы можете оставить ее плоской или сделать подобной дереву. Эта структура зависит фактически от ваших потребностей и энтузиазма в эксплуатации вашей собственной области. Наибольшая выгода для нас состоит в том, чтобы использовать вашу "домашнюю" среду для поддержки ваших работ и максимально уменьшить объем ручной работы. В следующих двух главах описано множество средств, которые могут работать с вашей личной файловой системой.

На рис.1-2 показана древовидная структура вашего регистрационного каталога. Эта планировка представляет каркас среды, который вы можете заполнить соответствующей информацией. По мере того, как растет ваше мастерство использования системы, вам могут понадобиться эти типы областей для размещения в них информации. Вы обнаружите также, что наш сценарий хранения информации предполагает движение по деревьям, или их обход, так что вам гарантируется выгода от использования иерархической конструкции.

Давайте пройдемся по этой примерной структуре и определим, каковы ее части. Данная структура включает много файлов и каталогов, но все они имеют определенное назначение. Возможно, вы не захотите использовать в точности эти имена, но вы получаете совет, какие типы категорий могут встретиться и как использовать систему для поддержки этой структуры.

Корнем этого дерева является регистрационный каталог, который определен в пятом поле файла /ets/passwd. Использование файла паролей описано в passwd(4). Вот пример парольного входа автора:

russ:.pDIPADYfIXBY:103:101:Russ Sage:/usr/russ:/bin/sh

Слева направо вы видите имя пользователя (russ), пароль (.pDI...), идентификатор пользователя (103), идентификатор группы (101), личный комментарий, имя регистрационного каталога (/usr/russ) и командный процессор shell, получаемый при входе в систему (/bin/ sh).



ПОСТРОЧНЫЙ РАЗБОР ПРИМЕРА ФАЙЛА НАСТРОЙКИ


Строки 3-8 делают хитрую установку главной подсказки - переменной PS1. В строке 3 инициализируется переменная, которая выбирает подсказку. Значение ushort жестко закодировано в файле, но вы всегда можете запросить его или установить его в зависимости от файла.

Первой альтернативой является ufull, используемая для установки подсказки в виде полного имени узла uucp в локальной системе. Вы выбираете такую подсказку, если используете несколько машин и для доступа к одной машине применяете другую. Отличительная подсказка напоминает вам, какой машиной вы пользуетесь. Отметим, что подсказка имеет одинаковое число символов и для короткой строки, и для длинной. Если же вам нужно имя узла uucp, но не нужна длинная строка для подсказки, вы можете выбрать ushort, что дает первые три символа имени узла. Как показано в строке 6, имя получается применением команды uuname для получения локального имени узла (опция -l). Затем это имя пропускается через команду cut, которая вырезает символы с первого по третий. Результат присваивается переменной подсказки.

Последняя альтернатива для тех из вас, кто имеет графические символы. Назначение в строке 7 есть греческий символ. Его можно получить применением специальных управляющих последовательностей, которые указывают терминалам отображение специальных символов. Символы ^[ являются визуальным представлением управляющего символа в программе vi. Вы можете получить этот символ в программе vi, набрав control-v, а затем ESC. Последовательность ESC[12m означает, что следующий символ будет напечатан как графический. Символ j является вашей подсказкой и превращается в графический символ, который выдается на ваш экран. Используя различные символы алфавита, вы можете иметь в виде вашей подсказки почти любой графический символ. ESC[10m возвращает ваш терминал в режим обычного текста, так что все символы, печатаемые после того, как вы набрали ESC[10m, являются нормальными.

Если вы хотите сохранить вашу пользовательскую подсказку для всех подчиненных интерпретаторов shell, экспортируйте ее. Иначе вы получите $ для всех интерпретаторов shell нижнего уровня.


Строка 10 присваивает переменной LOGNAME выход команды logname(1). Команда logname - это обычная команда системы UNIX, которая печатает ваше регистрационное имя из файла /etc/passwd. Обычно эта переменная установлена для вас системой, но данный пример показывает, как вы можете установить ее вручную.

Строка 11 инициализирует переменную HOME. Она тоже устанавливается для вас системой, но мы хотим показать, как делать эти вещи осознанно, а не по умолчанию. Сначала мы ищем в файле паролей запись, соответствующую переменной LOGNAME. Мы ищем от начала строки имя, которое завершается символом :, чтобы убедиться, что найдено только корректное соответствие имени пользователя. Затем вся запись посылается команде cut, которая вырезает шестое поле - регистрационный каталог. Преимущество такой стратегии в том, что регистрационный каталог автоматически меняется, если меняется запись в файле /etc/passwd.

Строка 12 инициализирует переменную MAIL. Определяя MAIL, вы указываете, что вы должны быть уведомлены о посылке вам новой почты, если вы находитесь в режиме on line. Строка 13 экспортирует эти переменные, так что они доступны нам в порожденных интерпретаторах shell.

Строки 15-24 определяют все каталоги первого уровня в нашем регистрационном каталоге. Большинство имен состоят из двух букв, некоторые из трех. Теперь мы можем применять команды такого вида:

$ cd $HD $ ls -R $HSR $ cu -ltty00 dir | tee $HBB/board/session$$

Строка 25 присваивает переменной HDIRS все имена каталоговых переменных, что облегчает подключение всех каталогов без повторного ввода их имен. Мы можем просмотреть все каталоги и напечатать размер используемого дискового пространства:

$ for DIR in $HDIRS > do > echo "disk usage for $DIR: `du -s $DIR`" > done

Строка 26 экспортирует переменные так, чтобы мы могли всегда их использовать. Отметим, что мы экспортировали $HDIRS и HDIRS. Перед тем, как выполнить экспортирование, $HDIRS было распространено на все различные имена переменных. Следовательно, фактически мы экспортировали все имена плюс саму переменную HDIRS.



Строка 28 инициализирует P так, чтобы это был ваш каталог в PUBDIR, то есть /usr/spool/uucppublic. Теперь у нас есть простой способ ссылаться на наши файлы при работе с командой uucp.

Строка 30 устанавливает CDPATH. Это путь, который проверяется, когда вы выполняете команду cd. Сначала проверяется текущий каталог (.) на предмет того, есть ли в нем имя каталога, в который вы хотите попасть. Затем проверяется .. (родительский каталог). После этого просматривается ваш регистрационный каталог. Последним назначением CDPATH является $HDIRS, что подключает имена всех подкаталогов. Цель этих имен - позволить команде cd искать в соответствующем каталоге введенное вами имя.

Например, если бы вы были в /etc и набрали "cd doc", вы бы попали в $HOME/doc, поскольку CDPATH содержало в себе $HOME. Аналогично, если бы вы имели подкаталог $HOME/doc/status и ввели "cd status" откуда-либо из другого места в системе, вы бы пришли в $HOME/doc/status, так как корень $HOME/doc был в CDPATH.

Порядок поиска в каталогах такой же, как объявлено в переменной CDPATH. Если вы вводите имя каталога, которое встречается более чем в одном месте, вы попадаете в первый каталог, обнаруженный при последовательном поиске. Например, если бы вы сказали "cd sys", то попали бы в $HOME/sys прежде, чем в $HOME/ src/sys.

В табл. 1-1 приведен пример эквивалентных команд cd, представленных в трех различных формах, которые понимает UNIX. То, какую форму вы используете, зависит от того, что считается наиболее удобным и требует как можно меньше нажатий клавиш.

Таблица 1-1 Три способа использования команды cd

Абсолютный CDPATH переменной Относительно
cd /usr/russ cd cd $HOME
cd /usr/russ/src/asm cd asm cd $HSR/asm
cd /usr/russ/doc/paper/conf cd paper/conf cd $HD/paper/conf
cd /usr/russ/tmp cd tmp cd $HT
Строка 31 инициализирует переменную PATH. PATH работает таким же образом, как CDPATH. Она ищет программы, которые нужно запустить, в каждом каталоге, указанном в переменной PATH. Если имя не найдено ни в одном из этих каталогов, печатается сообщение ": not found" ("<имя-файла>: не найдено").



Поскольку мы можем установить наш PATH как угодно, можно указать все таинственные места в системе, в которых расположены исполняемые модули. Когда мы хотим их выполнить, мы не обязаны их искать и набирать полное маршрутное имя. Чтобы дополнить PATH, введите, например, следующее:

PATH=$PATH:/usr/lib/uucp

Команда paths, представленная далее в этой книге, использует $PATH, чтобы сообщить нам, в каком каталоге размещен исполняемый модуль.

Строка 32 инициализирует переменную SHELL. Эту переменную могут использовать не более чем одна или две утилиты. Обычно она устанавливается системой, когда вы регистрируетесь. Строка 33 экспортирует переменные CDPATH, PATH и SHELL.

Строки 35-39 - это хитрый способ установки определений терминалов. Строка 35 начинается со спрятанной команды tty, заключенной в знаки ударения (`...`). Выходом команды tty является "/dev/tty00". Затем мы берем основное имя этой строки, т.е. "tty00". Далее мы используем структуру переключателя по этому значению, чтобы увидеть, что мы хотим сделать для каждого конкретного терминала. Команды tset, показанные здесь, относятся к среде XENIX и могут быть неприемлемыми в вашей среде.

Строка 41 делает эхо-отображение значения TERM на экран, чтобы сообщить вам тип вашего терминала, если он вам нужен. Это значение доступно, если описанная ранее команда tset устанавливает для вас TERM как часть своей обычной работы.

В строке 42 устанавливается переменная TERMCAP, указывающая на /etc/termcap. Это обычный способ установки переменной TERMCAP. Другой способ - присвоить TERMCAP текущую закодированную строку, которая находится в файле описания терминала. Если TERMCAP установлен на закодированную строку, то утилите vi нет необходимости обращаться к файловому вводу-выводу, чтобы получить характеристики вашего терминала. Строка 43 экспортирует эти значения так, чтобы они были доступны на любом уровне интерпретатора shell.

Строка 45 устанавливает частотную переменную. Это переменная из XENIX и, возможно, имеется в System V. Она используется для установки информации о времени.



Строка 46 устанавливает информацию о зоне времени, как это требуется в библиотечном вызове ctime(3). Имея переменную TZ, вы можете перекрыть подразумеваемую зону времени при доступе ко времени из программы на языке Си. Строка 47 экспортирует эти переменные.

Строка 49 устанавливает ваше значение маски пользователя (umask). Она управляет подразумеваемым разрешением доступа для всех файлов, которые вы создаете. Система вычитает значение umask из 777. Результат становится правом доступа к файлу, в данном случае 755. Когда вы создаете каталог с правом доступа 755, этот каталог показывается командой "ls -l" как rwxr-xr-x. Когда вы создаете некаталоговый файл с правом доступа 755, этот файл показывается как rw-r--r--, что эквивалентно 644. Некаталоговые файлы не имеют бита x, поэтому их нельзя исполнить. Каталогам же нужен установленный бит x, чтобы они были доступны по команде cd.

Строки 51 и 52 сообщают вам о времени вашего сеанса работы в системе. Строка 51 сообщает вам текущее время вашего входа в систему, а строка 52 вызывает программу lastlog, которая печатает дату вашей последней регистрации в системе. Программа lastlog описана в главе 5.

Строки 54-58 инициализируют переменные, генерирующие цвета на цветном мониторе. Управляющие значения являются стандартными значениями кодов ANSI. Это работает в системе XENIX и может работать в вашей системе. Растровая графика не доступна, но имеется символьная графика и различные основные (foreground) и фоновые (background) цвета. Основные цвета кодируются числами, начиная с 30, а фоновые цвета - числами с 40.

Строки 60-66 - просто для забавы. Они представляют собой хитрый способ устанавливать каждый день на экране различные цвета. Строка 60 начинается с запуска команды date и передачи ее выхода по конвейеру команде cut. Вырезается первое поле, которое является днем недели. Затем мы создаем структуру переключателя по строке дня, выполняя различные действия для каждого дня. Благодаря эхо-отображению управляющих последовательностей, монитор реагирует немедленно.


ТЕОРИЯ ОТНОСИТЕЛЬНОСТИ ВНУТРИ СИСТЕМЫ UNIX


Теперь, когда мы ознакомились с "домашней" средой, следующий шаг - обратиться к средам, находящимся вне регистрационного каталога ($HOME). Например, что представляют собой другие каталоги на том же уровне, что ваш $HOME ? Кто еще работает в системе? Как попроще получить доступ к их каталогам? Можете ли вы запускать программы в чужих каталогах? Такого рода вопросы и действия относятся к другим людям в вашей системе.

Единственный способ ответить на эти вопросы - посмотреть вокруг себя. Никто не собирается рассказывать вам, что такое система. Вы должны сами исследовать ее и выяснить, куда вы можете ходить, а куда нет. Система конечна, так что вы можете себе помочь, делая распечатки всех каталогов и файлов.

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

Ниже показаны некоторые примеры относительных команд.

ls -l $HOME/.. перечисляет файлы в моем родительском каталоге.

cd ../../.. в предположении, что текущим каталогом является /usr/russ/src/c, делает моим текущим каталогом /usr.

ls . перечисляет файлы в текущем каталоге.

ls .. перечисляет файлы в моем родительском каталоге.

$HOME/../../bin/ls запускает ls в каталоге /usr/russ/../../bin, т.е. в /bin/ls.

../fred/bin/ls запускает команду ls в каталоге двоичных модулей Фреда, который имеет тот же родительский каталог, что и я, т.е. /usr/fred/bin/ls.



ТРЮКИ С ГЛАВНЫМИ ФАЙЛАМИ


Вот программы и файлы, которые вы можете разработать во время использования данной книги. Файл .lastlog содержит даты каждого вхождения в систему с вашими учетными данными. Программа, которая управляет этим файлом, называется lastlog и представлена в главе 5.

Следующий файл - .trashcan. Это каталог, который временно хранит файлы, удаленные вами. Если вы уверены, что они вам не нужны, то их можно удалить навсегда. Эта особенность рассмотрена в главе 3. Последний файл - .phone.list. Это ваша личная база данных со списком телефонов. Она обслуживается командой phone (см. главу 5).



УРОВЕНЬ 0 - АППАРАТНЫЕ СРЕДСТВА


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

Отметим, что хотя прогресс на этом уровне продолжается, это вызывает очень малые изменения на верхнем слое пирамиды. Философия системы UNIX состоит в том, чтобы изолировать низкоуровневый аппаратный слой и обеспечить единообразные интерфейсы к нему, которые не нуждаются в изменениях "наверху". Верхний слой даже не должен знать о нижнем слое. Это не значит, что события в мире аппаратуры не важны в реальном мире, ведь противоречия реального мира влияют на скорость и емкость ресурсов, не говоря уже об их стоимости.



УРОВЕНЬ 1 - МИКРОКОМАНДЫ


Этот уровень во многом похож на язык программирования. Он является инструментом, который использует архитектор системы для создания "родного" машинного языка. Машинный язык сообщает аппаратуре, какую конкретную команду следует выполнить.

В начале эволюции ЦП большинство наборов команд были аппаратно кодированными. Это значит, что когда ЦП получал команду, декодирование и выполнение производилось непосредственно цепями в кремниевой микросхеме. Благодаря прогрессу в технологии ЦП, некоторые микросхемы могут быть программируемыми на уровне исполнения команд, что позволяет конструкторам создавать и реализовывать новые наборы команд с минимальными усилиями.



УРОВЕНЬ 2 - УСЛОВНАЯ МАШИНА


Данный уровень обеспечивает трансляцию из мнемоник языка ассемблера в коды операций и данные машинного языка. Язык ассемблера - это некоторая англо-подобная нотация, которая облегчает человеку понимание и управление работой компьютеров.

Условная машина поддерживается ассемблером. Ассемблер может превращать идеи более высокого уровня в цепочки чисел, которые могут быть затем выполнены. Наряду с ассемблером, применяются модели, помогающие использовать аппаратуру компьютера. Здесь мы можем определить такие вещи, как стеки, вектора прерываний и периферийный ввод-вывод.



УРОВЕНЬ 3 - ЯДРО


Ядро является следующим логическим продвижением вверх и концепцией, которую можно теперь реализовать программно на условной машине. Ядро предоставляет среду, поддерживающую еще большие абстракции, чем те, что рассматривались до сих пор. Двумя наиболее важными абстракциями на уровне ядра являются управление процессами для мультипрограммирования и многозадачности, и файловая система, которая управляет хранением, форматом, поиском файлов и т.п. Когда эти две области переплетаются, мы имеем базовую функцию многопользовательской машины и ядро операционной системы.

Одной из наиболее важных областей, которыми управляет ядро, является безопасность. Проверки идентификации пользователя выполняются в системных вызовах внутри ядра. Определенные механизмы используются ядром для управления безопасностью файлов, устройств, памяти и процессов. Единственный способ отключить механизмы безопасности состоит в изменении исходного кода ядра и перекомпиляции всей системы, что крайне нежелательно.



УРОВЕНЬ 4 - ОПЕРАЦИОННАЯ СИСТЕМА


Данный уровень строится на ядре, чтобы создать полную операционную среду. Потребность в дополнительных функциях системы можно удовлетворить созданием автономных программ, имеющих конкретное назначение. Таким образом, совокупность всех специфических функций определяет операционную систему.



УРОВЕНЬ 5 - КОМПИЛЯТОРЫ


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

С помощью компилятора мы можем определить совершенно новый язык и сделать его рабочим на компьютере, написав компилирующую программу, которая читает этот новый язык. Это открывает целые новые области во взаимодействии человека с машиной. Высокоуровневые языки могут воплощать различные подходы к решению задач, например, процедурную модель или объектно-ориентированную модель, и в конце концов, очевидно, могут достичь выразительной мощи разговорного языка типа английского.



УРОВЕНЬ 6 - ПРИКЛАДНЫЕ ПРОГРАММЫ


В наше время прикладные программы могут означать массу разнообразных вещей. Мы можем предположить, что любая программа, которая сделана с помощью компилятора, является прикладной программой. Примерами возможных прикладных программ являются следующее поколение языков, интерпретаторов и генераторов прикладных программ. Интерпретатор - это программа, написанная на распространенном языке высокого уровня, которая может декодировать и исполнять другой синтаксис (или язык). Примером, который интересует нас в системе UNIX, является командный процессор shell. Это программа на языке Си, созданная для чтения и исполнения команд, записанных по правилам синтаксиса, определенных командным процессором shell.

Генератор прикладных программ - это программа, написанная на языке высокого уровня. Она предназначена для получения достаточной информации от пользователя о его приложении и может использовать компиляторный язык, например Си, для написания прикладной программы, реализующей то, что требуется. Пользователь ничего не программирует. Выходом генератора является рабочая программа.

UNIX не делает особых различий между уровнями. Некоторые особенности системы, например, конвейеры, являются частью ядра на нижнем уровне. Команда типа cat выполняет довольно простую функцию на уровне операционной системы. Нечто подобное ls напоминает простую прикладную программу с относительно малым набором опций. Большие программы, подобные семейству roff, определенно являются полновесными приложениями, а средства типа sed и awk являются фактически интерпретаторами небольших языков программирования. Замечательной особенностью системы UNIX является единообразие, которое она вносит в этот широкий диапазон функций.



УРОВЕНЬ 7 - КОМАНДНЫЕ ФАЙЛЫ


Этот верхний уровень является языком, который интерпретирует программа /bin/sh (в случае командного процессора Bourne shell). Ее синтаксис поддерживает полный язык программирования. Хотя этот язык лишен ряда встроенных структур и функций современного языка высокого уровня, он имеет все необходимое для написания полезных программ. Большим плюсом является то, что языку командного процессора доступны в качестве внешних функций любые средства, утилиты и программы, которые имеются в системе UNIX. Это значит, что алгоритмы, которые могут потребовать сто или более строк на языке низкого уровня типа Си, язык командного процессора может выразить в двадцать строк. За счет потери производительности, разумеется.



ВАШ "РЕГИСТРАЦИОННЫЙ КАТАЛОГ"


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

Помимо определения вашего места в системе, можно привязать "домашний" каталог (home-catalog) к вашим точным спецификациям. "Регистрационный каталог" - это не только область файловой памяти, но и вся ваша среда. Можно установить переменные командного языка для определения путей по системе. Можно создать инструментарий, чтобы помочь вам в работе.



ВТОРОЙ СЛОЙ


Второй слой каталогов размещается под /usr. Как упоминалось ранее, /usr используется как точка монтирования для другой файловой системы. Это значит, что все файлы, которые имеются в /usr, находятся в другом разделе загружаемого диска или вообще на другом диске.

Первым каталогом является adm, для администрирования. Он содержит учетные файлы и регистрационный файл для su (суперпользователя), а также другие административные файлы.

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

Почти все исполняемые модули распределены между этими двумя каталогами. Другие исполняемые модули рассеяны по всей системе, например /usr/lib/uucp/uucico и /usr/lib/ ex3.7preserve.

Далее games. UNIX приходит с ассортиментом интересных игр. Большинство из них текстовые, но предоставляется несколько программ графического типа, например worm, worms и rain.

Каталог include содержит все файлы-заголовки. Файлы-заголовки используются в программах на языке Си для определения структур и системных присваиваний, полезных для программирования. Здесь имеется подкаталог sys, который содержит все файлы= заголовки, относящиеся к системе. Читая эти файлы-заголовки, можно многое узнать о системе UNIX.

Следующий каталог - lib, который содержит библиотечные файлы для всех видов "имущества": файлы печатающих устройств, файлы поддержки утилиты vi, другие языки и uucp. Каталог /usr/ lib представляется складом всяких библиотек, которые имеются в системе, отличных от библиотек компилятора.

Каталог lost+found находится здесь для той же цели, что и одноименный каталог корневого уровня. Каждая файловая система должна иметь такой файл. Без него fsck не имеет временного места для размещения полуудаленных файлов и поэтому удаляет их навсегда.

В каталоге mail находится ваш системный почтовый ящик. Когда вы запускаете команду mail, здесь накапливается очередь сообщений. В каталоге usr/mail каждый файл носит имя пользователя. В этом файле хранится почта пользователя, пока он не прочитает ее.


Каталог man предназначен для активных страниц руководств по системе UNIX. Наличие постоянного доступа к страницам руководств является хорошим средством. Однако, эти страницы занимают много места, и доступ к ним может потребовать довольно много времени при сильно загруженной системе.

В каталоге news хранятся все файлы новостей. Эти файлы именованы в соответствии с порядком, в котором они были введены в каталог. Команда news(1) смотрит на дату файла $HOME/ .news_time, чтобы сообщить, какие новости вы еще не читали.

Каталог preserve предназначен для файлов, связанных с утилитой vi. Они помещаются сюда, когда вы работаете с vi или с редактором ex и пропадает питание машины либо ваш сеанс работы прерывается в виде "зависания". Когда в системе восстанавливается питание, /tmp содержит файлы редактора ex. Из каталога /etc/rc запускается утилита /usr/lib/ex3.7preserve, которая просматривает /tmp, преобразует его в сохраненный файл и помещает его в /usr/preserve. Когда вы входите в систему, вы получаете почту о том, что у вас имеется сохраненный файл редактора, который вы можете восстановить и поместить его на исходное место.

Каталог pub не содержит ничего особенного, обычно в нем просто некоторые информационные файлы вроде таблицы ASCII или греческих символов.

Каталог spool - это главная точка входа для всех буферизованных файлов в системе. В этом каталоге имеется много подкаталогов, содержащих специфические типы буферизованных файлов. Некоторыми типичными подкаталогами являются lp, uucp и uucppublic.

В каталоге src хранится исходный код системы UNIX, если он имеется в системе. От этого каталога ответвляется много уровней: команды, библиотеки, код ядра, код машинного языка и автономные утилиты. Часто в /usr/src хранится также исходный код для локальной машины.

Каталог sys традиционно хранит файлы, необходимые для генерации нового ядра. Это файлы-заголовки, конфигурационный файл, библиотеки и командный файл для создания нового ядра из всех этих файлов.

Последний каталог - tmp. Это вторичная временная область хранения, которая используется не так часто, как /tmp. Ее, однако, использует утилита sort.


В данной главе рассматривается среда,


В данной главе рассматривается среда, которая существует в системе UNIX и вокруг нее. Освещение всех аспектов среды UNIX было бы слишком громоздкой задачей и выходит за пределы данной книги. Даже отдельным утилитам, таким как fsdb и sdb, нужны свои собственные книги, чтобы отдать им должное. Мы пытаемся дать читателю начальные сведения, философию и ощущение системы UNIX, что лежит в основе исследований и инструментов, представленных в этой книге.
Читая эту главу, вы, возможно, захотите прочитать (или перечитать) команды profile(4), environ(5), term(5), termcap(5) и termio(7) в руководствах по UNIX, чтобы ознакомиться с механизмами, которые предоставляет UNIX для установки рабочей среды.
Внутри системы UNIX существует множество различных подсред. Все вместе они образуют общую картину, в виде которой мы представляем себе UNIX. Эта книга посвящена наиболее важным аспектам среды UNIX с целью закладывания фундамента, необходимого для понимания всей системы. Это даст вам контекст, в котором можно посмотреть на собственную работу в системе, независимо от того, являетесь вы пользователем, программистом или администратором системы.
В данной главе рассматриваются различные среды в компьютерах с теоретической точки зрения, описывается "домашняя" среда и методы ее установки, способы использования условных обозначений и глобальная среда.

ЖИЗНЬ СИСТЕМЫ UNIX: НЕКОТОРЫЕ МЕТАФОРЫ


UNIX - это особый мир, живущий своей жизнью. Его социальная структура имитирует реальную жизнь, с правительством, содержащим правителя (корень root), штатом поддержки (bin, cron, lp, sys) и массами (/usr/*). Массы не имеют доступа к мощи правителя, если не используют предварительно установленных средств (/bin/su) или не занимаются криминальными действиями и нарушением мер безопасности. Как и в любом обществе, большая многопользовательская система UNIX устанавливает права и обязанности своих пользователей.

При входе в систему пользователь получает свое "место под солнцем" (регистрационный каталог - $HOME ). Это место зависит от того, что было раньше (от родительского каталога ..), а будущие места зависят от того, что происходит позже (каталоги, подчиненные $HOME). Работа распределяется по организациям и иерархиям в зависимости от их функций в обществе (все пользователи в /usr, все транзитные файлы в /usr/spool, все функции безопасности в /etc). Посмотрите вокруг себя в вашей системе, чтобы ознакомиться с вашим миром. Вы можете после этого выбрать, участвовать ли в некоторой части этого мира или игнорировать ее.

Движение людей в системе UNIX происходит параллельно. Некоторые области (/tmp) доступны всем, а некоторые области сильно охраняются от большинства людей (/etc/passwd). Транспортная служба может перевезти наши вещи (передача файлов по сетям uucp). Мы даже можем воспользоваться общественным транспортом, чтобы добраться в разные части города (вход в другие системы (rlogin), эта особенность имеется только в BSD).

В мире UNIX нам доступны различные пути. Эти пути помогают нам сформировать свою судьбу (дисковые разделы, монтированные в любое место файлового дерева). Когда дисковый пакет монтируется, он становится доступным нам. Когда он демонтируется, мы теряем доступ к нему. Когда запускаются процессы, они проходят через различные этапы своей жизни. Они рождаются (ответвляются), растут (становятся планируемыми и помещаются в таблицу процессов) и, наконец, становятся производительными рабочими в обществе (переходят в состояние запуска и выполняются).


Все процессы имеют фамильное дерево. Порожденный процесс всегда имеет родителя, а родительские процессы могут порождать много "детей". В зависимости от приложения, они могут быть "дедами" и "внуками". Процессы "умирают" так же легко, как создаются. Одной из необычных вещей в мире UNIX является то, что "дети" почти всегда "умирают" раньше своих "родителей".

Правительство (ядро) проводит в жизнь параметры среды, которые выглядели бы в довольно тоталитарном духе, если бы это было в реальном мире. Только определенное число рабочих допускается к рабочему месту одновременно (это максимальное количество ячеек в таблице процессов). Рабочие ограничены в числе "детей", которых они могут иметь (максимальное количество процессов на пользователя). Поскольку рабочие накапливают материальные ценности, они ограничены в количестве товаров, которые они могут поместить в комнаты своих домов (максимальный размер файла, или ulimit). Хотя не установлен лимит на число различных файлов (комнат) максимального размера, которые могут существовать, вся система имеет предел (df показывает свободное пространство), и одна ненасытная персона может нанести удар по окружающим. Здесь возникает своего рода экология.

Так же, как компьютерный век проходит под присмотром электронной автоматики, так и UNIX ведет таблицы о деятельности всех пользователей. Механизмы учета организованы правительством (внутри ядра) и всегда записывают действия каждого пользователя. Тем не менее, это свободное общество в той мере, что вы можете получить распечатку о вашем кредитном состоянии (используя acctcom для печати учетных записей). Хотя система UNIX имеет негативные аспекты (как и человеческое общество), в ней есть также некоторые очень позитивные особенности. Гибкость системы и богатство инструментов дает нам очень продуктивную и детально разработанную рабочую среду. Наша производительность в этом смысле ограничена в основном нашим собственным воображением. Когда работа становится слишком утомительной и скучной, мы всегда можем создать средства, делающие за нас эту работу. Это обстановка свободной инициативы, в которой хорошие идеи могут дать значительное увеличение производительности.


Lc - вывод файловой информации на экран по столбцам


ИМЯ: lc

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



M - простой доступ к команде more


ИМЯ: m

m Простой доступ к команде more



Kind - вывод однотипных файлов


ИМЯ: kind

kind Выдача списка имен файлов определенного вида



КОМАНДА cut ДЛЯ BSD


В системе BSD нет команды cut, но следующий командный файл все же "вырезает" первое непустое поле в текущем аргументе. Предположим, мы используем команду для генерации целого набора строк. В данном случае это команда who:

for NAME in 'who | sed "s/^\([^ ]*\).*/\1/"' do done

Для каждой обнаруженной строки (аргумента) команда sed должна подставить вторую строку символов вместо первой строки. Первая строка - это строка, которая вырезается. Мы ищем от начала строки (^) символ, отличный от пробела ([^ ]), за которым следует любое число непустых символов (*). Эта операция прерывается по достижении пробела. Набор непустых символов ограничивается обратными косыми чертами \( и \). Впоследствии ссылка на этот набор дается в виде \1. Символы .* означают, что после того, как найден пробел, необходимо считать подходящими все символы до конца строки. Мы находимся фактически сразу после того, что заключено в пару символов \( и \). Группируя первый набор символов, отличных от пробела, мы получаем то, что является результатом работы команды "cut -f1".

В этом месте мы подходим к знакам ударения (`), окаймляющим все выражение. Они берут результат работы всех команд, заключенных в знаки ударения и передают на следующую охватывающую структуру в наших вложенных выражениях. Этот следующий уровень окаймления указан кавычками. Кавычки превращают символ в строку, чтобы его можно было сравнить с символом "-". Следующий слой - квадратные скобки, указывающие условие для оператора if. Это приводит к тому, что генерируется нулевое (истина) или ненулевое (ложь) условие, которое управляет тем, будет ли выполнена часть then оператора if-then.

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

Остальная часть командного файла представляет собой один огромный оператор выбора (case). Аргументом, используемым для ветвления, является число позиционных параметров в командной строке. Если позиционных параметров нет, то в строках 11-19 активируется цикл while. Заметим, что цикл while выполняет оператор чтения, но не указывает, откуда дол- жен быть взят его вход. Это связано с тем, что входом по умолчанию является стандартный ввод (stdin). Для каждого имени файла, которое читается из стандартного ввода, запускается команда file системы UNIX. Выход команды file передается по программному каналу команде fgrep (а не grep, что увеличивает скорость), чтобы посмотреть, является ли файл текстовым.


Фактический выход команды fgrep перенаправляется на нулевое устройство (в бесконечную область памяти), поскольку он нам не нужен. Нас интересует лишь код возврата после выполнения всего конвейера. Если команды file и fgrep отработали успешно, кодом возврата является ноль. Это истинное значение, поэтому выполняется участок цикла после then (строки 14-17). Если файл не существует или не является текстовым, то код возврата ненулевой, и условный оператор завершается. Это приводит нас в конец цикла, выполняется следующая итерация цикла while и мы рассматриваем следующий аргумент из стандартного ввода.

Теперь рассмотрим обработку, выполняемую по then (строки 14-17). Для каждого файла, который является текстовым, печатается строка двоеточий (:) до и после имени файла, а команда head системы UNIX печатает первые 15 строк. Такой сценарий продолжается, пока не закончатся данные в стандартном вводе.

Рассмотрим другую альтернативу, покрываемую данным оператором выбора. Она обрабатывает ситуацию, когда имеется несколько позиционных параметров (что указано символом * в операторе case). Цикл for пробегает все параметры (строка 20). Звездочка (*) в операторе case означает, что подходит любое значение, которое не подошло ранее. Это улавливающая (catchall) опция. Цикл for использует аргумент $* в качестве своего входа. Он представляет значения всех позиционных параметров, что является фактически всей командной строкой, исключая имя утилиты. Команда find используется для поиска всех нормальных файлов в каталоге. "Нормальные" файлы не означает "только текстовые файлы", поэтому мы проверим это позже. Выход команды find передается по каналу команде sort, чтобы сделать его более наглядным. Отсортированный список передается по каналу в цикл while, который помещает имя файла в переменную FILE (строка 27). Проверяется, текстовый ли файл, затем он печатается командой head.

Если мы сравним строки 13-18 и строки 24-29, то мы увидим, что это один и тот же код. В большинстве языков программирования это означало бы, что мы должны оформить эти строки как процедуру и вызывать ее, когда нужно. Язык программирования интерпретатора shell, хотя и довольно мощный, не имеет хорошего способа реализации процедур. Последний интерпретатор shell в System V имеет функции, которые позволяют решить эти проблемы. Отметим, что внутренний цикл while повторяется на каждом файле, который существует в определенном каталоге, а внешний цикл for проходит от каталога к каталогу.


КОМБИНИРОВАНИЕ ПРОДУКТИВНЫХ ИДЕЙ


Две концепции являются общими почти для всех файловых инструментальных средств. Первая - это идея рекурсивного поиска, которая означает, что некоторые команды системы UNIX (например, find) просматривают все файловое дерево, начиная с некоторой заданной начальной точки (или с текущего каталога). Если в данном каталоге встречается подкаталог, то его содержимое тоже исследуется - и так далее вниз к самому нижнему под-подкаталогу. Так проходятся маршруты ко всем файлам в целом дереве.

Стандартные команды системы UNIX обеспечивают только ограниченное число основных функций, которые могут работать рекурсивно по всему файловому дереву. Наша стратегия при создании инструментальных средств в этой главе - воспользоваться преимуществами такого рекурсивного поиска и распространить их на многие другие функции.

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

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



Ll - вывод файловой информации в длинном формате


ИМЯ: ll

ll Выдает список файлов в длинном формате



Mmm - обработка программой nroff макрокоманд для рукописей


ИМЯ: mmm

mmm Командная строка nroff для макросов обработки рукописей



Зачем нам нужен командный файл


Зачем нам нужен командный файл tree?
Как мы уже отмечали, вся система UNIX строится вокруг файловой системы, которая похожа на дерево. Дерево, с которым мы работаем в системе UNIX, растет вверх ногами: корень находится вверху, а ветви и листва растут вниз от корня. Физическая структура реальных деревьев и файловых деревьев, используемых в системе UNIX, очень сходна: один корень (начальная точка) и один ствол. Как глубоко и как далеко могут уходить ветви от основного ствола - не ограничивается ничем, кроме ограничений физического пространства. Аналогично, число листьев, которые может иметь каждая ветвь, фактически не ограничено.
Многое в системе UNIX задумано для того, чтобы приспособиться к дереву. Некоторые команды обходят дерево и сообщают о его компонентах, но обычно их сообщения выдаются в форме, не очень удобной для чтения человеком. Это делает командные файлы весьма мощными инструментами. Перевести необработанные, недружественные сообщения командных файлов в удобный, информативный вид довольно легко.
Команда tree является комбинацией команд системы UNIX, которые представляют логическую файловую структуру в наглядной форме. Эта команда полезна для получения глобальной картины файлов, их расположения в иерархической структуре файлового дерева, гнездовой структуры каталогов и подкаталогов.
Что делает tree?
Команда tree - это постпроцессор для команды UNIX find. Find просматривает сегмент файлового дерева и полные имена всех файлов, которые соответствуют заданному критерию. Команда tree использует утилиту sed системы UNIX, чтобы перевести выход команды find в наглядную форму.
Входным параметром для команды tree является имя каталога, которое может быть указано в любом абсолютном виде, например, /usr/spool/uucp, или в относительном, например, ../../bin. Если никакого имени не указано, подразумевается ., что является текущим каталогом.
Имя каталога является началом (или корнем) отображаемого дерева. Чтобы показать глубину дерева, все файлы, подчиненные данному каталогу, отображаются с отступом. Для удобства представления гнездовой структуры, между следующими друг за другом ответвлениями печатается косая черта (/).


Зачем нужен командный файл thead?
Как уже объяснялось ранее в этой главе, иерархическая файловая система является очень значительной частью системы UNIX. Однако, только несколько команд в UNIX имеют дело непосредственно с рекурсивным поиском файлов. Единственный способ расширить возможности системы создать новые рекурсивные утилиты, работающие с файлами. В данном случае мы соединим нашу стратегию поиска по дереву с командой head системы UNIX для упрощения идентификации содержимого всех файлов в выделенном сегменте файлового дерева.
Иногда у нас, возможно, будет возникать желание просмотреть файлы в более чем одном каталоге. В больших проектах разработки программного обеспечения файлы обычно создаются в нескольких иерархических каталогах. Thead может работать со множеством путей доступа и выводить заголовки (несколько первых строк файлов) в виде непрерывного потока.
Что делает thead?
Thead - это препроцессорная команда к команде head системы UNIX. Команда head очень примитивна, но, добавляя к ней управляющую структуру и логику, мы можем создать очень полезное инструментальное средство, которого нет в стандартной среде UNIX.
Например, мы захотели просмотреть заголовки всех текстовых файлов в нашем регистрационном каталоге. Если у нас имеется большое число подкаталогов, нам необходимо все их пройти и просмотреть все файлы, содержащиеся в них. Мы можем сделать это с помощью команды
$ thead $HOME
Если мы хотим просмотреть только исходные файлы на языке Си (*.c), то представленный выше синтаксис не годится для этого. Он не обладает достаточной гибкостью. Нам необходимо иметь способ указать (или квалифицировать) файлы в $HOME перед тем, как просматривать их. Так как команда thead может воспринимать полные имена файлов, мы можем использовать следующую команду:
$ find $HOME -name "*.c" -print | sort | thead

Команда find генерирует список файлов с расширением C, который сортируется и подается по каналу на вход команде thead. Как видно из представленных двух примеров, весьма полезной для командного файла является возможность получать входные данные либо из аргументов командной строки (как в первом примере), либо по программному каналу (как во втором примере). Способность использовать программный канал позволяет вам применять какие-либо другие команды системы UNIX, которые могут отбирать входные данные для вашего командного файла. Команда с такой двойной возможностью называется ФИЛЬТРОМ. Среди стандартных команд системы UNIX вы найдете лишь несколько команд-фильтров, таких как wc, awk, sort.


Зачем нам нужен командный файл tgrep?
Как мы могли видеть на примере двух предыдущих утилит, рекурсивный просмотр файлов очень полезен. Он сохраняет время, поскольку позволяет избежать поиска файлов вручную, а также создает средства, которые могут быть использованы в более мощных утилитах. Чем больше имеется созданных нами средств, тем больше новых средств мы можем построить с их помощью. Единственная проблема заключается в том, что вы должны позаботиться об их взаимозависимости (каким утилитам или средствам требуются другие утилиты или средства и кто на кого влияет). Еще одна область, где UNIX не имеет "родной" рекурсивной команды - это обработка строк. Семейство команд типа grep очень велико, но все они работают только по одному фиксированному маршрутному имени файла. Нам необходим препроцессор для команды grep. Правда, мы можем дать запрос на все файлы во всей системе или какой-либо ее части по нашему выбору. Если мы попытаемся сделать это вручную, то это означает, что мы должны много раз нажимать на клавиши, что может привести к синтаксической ошибке. Вы также должны точно помнить, как вы создавали командную строку, если вы в следующий раз захотите выполнить такую же задачу. Зачем выполнять грязную работу? Для этого существует компьютер.
Создавая программу автоматического обхода дерева файлов, мы освобождаемся для того, чтобы направить нашу энергию на более важные вещи вместо того, чтобы выпутываться из ситуации в случае какого-либо слишком специфичного синтаксиса. Один раз создав достаточно мощные средства доступа к файлам, мы можем посвятить наше время написанию программ, обрабатывающих файлы данных для решения каких-либо задач.
Что делает tgrep?
Основным предназначением tgrep является обеспечение большей гибкости и легкости использования возможностей команды grep. Ее синтаксис точно такой же, как и у grep, за исключением допустимых типов файлов. В команде grep UNIX в качестве аргумента может указываться практически любой файл, но указание текстового файла имеет наибольший смысл. В команде tgrep также могут использоваться текстовые файлы, но наибольший смысл имеет указание каталогов, поскольку мы ищем имена файлов. Команда find работала бы не очень хорошо, если бы пыталась извлечь множество имен файлов из текстового файла. В командной строке может указываться множество имен каталогов, поскольку все они используются как начальное место поиска оператора find.
По умолчанию tgrep находит все обычные файлы. В этой программе нет никакой проверки на то, текстовый файл или нет, поскольку мы не пытаемся напечатать все на экран. Поэтому мы ищем строки символов во всех файлах, начиная от архивных и заканчивая исполняемыми. Если вы хотите выбрать типы файлов, используйте две опции, -c и -h. Опция -c заставляет команду UNIX find искать только файлы с именами вида *.c. Аналогично, опция -h соответствует файлам *.h. Эти опции могут быть полезны для управления программами на языке Си, с которыми мы более детально познакомимся в главе 4. Эти опции не самое важное, но они показывают, как легко добавить новые опции в программу. Если при вызове была указана какая-то иная опция, кроме упомянутых, выводится сообщение об ошибке и программа останавливается. Подобно thead, tgrep является фильтром.


ЗАЧЕМ НАМ НУЖЕН КОМАНДНЫЙ ФАЙЛ paths?
В нашей среде интерпретатора shell переменная с именем PATH содержит имена каталогов, отделенные друг от друга символами двоеточия (:). Каждый раз, когда вы вводите команду после приглашения shell'а, интерпретатор shell, начиная с первого каталога, указанного в переменной PATH, смотрит, находится ли введенная вами команда в этом каталоге. Если да, то команда выполняется. Если нет, то shell идет в следующий каталог, указываемый переменной PATH, и так далее, пока не будут проверены все каталоги. Если команда все же не будет найдена, то вы получите следующее сообщение об ошибке:
| | $ whatchamacallit | sh: whatchamacallit: not found | |
Такой поиск команды осуществляется автоматически, но сама система не сообщает вам, ГДЕ размещена команда. Нам необходима утилита, которая ищет и выводит на экран маршрут к указанному файлу. Имея такую утилиту, вы можете использовать кратчайшие пути получения того, что вам нужно, и выполнять множество различных трюков. Вы можете комбинировать подобную команду с другими командами для создания гораздо более мощных средств. С маршрутом можно также комбинировать команды more, ls, file и cd системы UNIX. Возможно, вы обнаружите и другие команды по мере экспериментирования.
Команда, несколько похожая на ту, которую мы ищем, существует где-то в мире системы UNIX Systev V. Например, в системе AT&T это команда where. В системе UNIX Berkeley это команда which (текст на языке Си-shell'а) или whereis (исполняемая программа). Whereis дает дополнительную информацию, такую как место размещения файлов с исходными текстами (в каталоге /usr/src). Увидев, как мы создаем нашу собственную команду поиска маршрута, вы можете модифицировать ее для обеспечения работы с особенностями некоторых других команд и приспособить такие вещи к вашим нуждам.
Прежде чем мы удовлетворим свои прихоти, давайте бегло глянем на команду path, более простую, чем paths. Вся программа выглядит примерно так:
IFS="${IFS}:" for FILE in $@ do for DIR in $PATH do if [ -f $DIR/$FILE ] then echo $DIR/$FILE fi done done


ЗАЧЕМ НУЖЕН КОМАНДНЫЙ ФАЙЛ kind?
Файловая система UNIX имеет строгие стандарты при рассмотрении файлов. Имеется три вида файлов: обычные файлы (тексты, данные, исполняемые файлы), каталоги и устройства. Каждый вид файлов имеет свое предназначение и обычно имеет особые команды или файлы данных, которые работают с ним.
Давайте рассмотрим, как некоторые из существующих команд системы UNIX рассматривают типы файлов. Команда ls делает различие между каталогами и другими файлами, поэтому она может быть полезна. Другой важной командой является команда file. Она сообщает вам, какой тип имеет данный файл, что потенциально полезно, но слишком мало. Для того чтобы извлечь из команды file какую-либо полезную информацию, вы должны надстроить над ней некоторую программу. Что нам действительно нужно, так это некий гибрид команд ls и file, т.е. утилита, которая выводит имена всех файлов указанного типа.
Примером полезности такого рода утилиты может служить анализ содержимого каталогов. Возьмем, например, каталог /etc. Он содержит программы, файлы данных и текстовые файлы. Для каждого из этих типов требуется свой собственный тип анализа. Программы анализируются командами ls, size, nm и file. Файлы данных анализируются командой od.
Текстовые файлы анализируются командами more, wc, head, tail и другими. Таким образом, обычно вам необходимо работать в данный момент времени с файлами какого-нибудь одного типа.
ЧТО ДЕЛАЕТ kind?
Командный файл kind - это утилита, которая распечатывает имена всех файлов, имеющих указанный тип. Она имеет интерфейс, похожий на интерфейс команды ls, т.е. вы можете передать ей опции и имена файлов или символы расширения имен файлов. При выводе отображаются полные имена, если они были указаны, но вы можете избежать появления лишней информации при выводе, если предварительно перейдете в нужный каталог с помощью команды cd. Например, если бы я находился в моем регистрационном каталоге (/usr/russ) и ввел команду
$ kind -d /etc/* то вывод мог бы выглядеть так: | | /etc/mnttab | /etc/utmp | /etc/wtmp |


Зачем нам нужен командный файл ll?
Мотивы для создания команды ll те же, что мы обсудили ранее для команды lc. Мы можем использовать ll для нескольких целей. Она уменьшает количество требуемых нажатий на клавиши, позволяет избежать необходимости помнить специальные опции и вообще настраивает систему соответственно нашим требованиям вместо того чтобы нам приспосабливаться к системе.
Что делает ll?
Основой этой команды является известная команда "ls -l". Она, если вы помните, дает очень емкую информацию о каждом файле, включая права доступа, связи, имя владельца, размер и так далее. (Кстати, программисты, использующие язык Си, могут получить эту информацию при помощи системного вызова stat(2).) Поскольку такой список при наличии множества файлов может легко переполнить экран, то предоставляется опция -m. Она обеспечивает постраничный вывод с помощью команды more. Отметим, что если используется эта опция, то она должна стоять первой. Строка символов, соответствующая этой опции, удаляется командой shift, так что она не смешивается с именами файлов и обычными опциями команды ls, которые передаются как аргументы.
После опции -m (если она есть) ll допускает указание любых других допустимых опций команды ls. Можно также использовать любую комбинацию имен файлов. Здесь применимы обычные средства порождения имен файлов: * соответствует любым символам, ? - одному символу, а символы [] задают диапазон из некоторого набора символов. В итоге мы получили команду ls, которая по умолчанию работает как "ls -l", вызывает команду more с помощью одной опции вместо необходимости указания конвейера в командной строке и при этом сохраняет гибкость команды ls.

Pall - печать всех файлов в дереве


ИМЯ: pall

pall Распечатка всех файлов в дереве каталогов



Paths - нахождение пути доступа к исполняемым файлам, со специальными опциями


ИМЯ: paths

paths Определитель маршрутных имен файлов со специальными опциями



ПЕРЕМЕННЫЕ СРЕДЫ ВЫПОЛНЕНИЯ


FILE Содержит имя каждого файла
NAME Имя каталога, заданное в командной строке


FILE Содержит имя каждого файла
OPT Содержит специальные опции команды find
STRING Временная переменная, в которой содержится строка поиска




ARG Содержит каждый аргумент командной строки
DIR Элемент с именем каталога в переменной PATH
FILE Содержит имя каждого файла в командной строке
FORMAT Тип требуемого формата выходных данных
IFS Переменная shell'а, разделитель полей
PATH Переменная shell'а, пути к каталогам исполняемых модулей




MORE Содержит программный канал к команде more




MORE Содержит строку передачи результатов по конвейеру команде more




FILE Содержит имена файлов по мере их чтения из stdin (стандартного ввода)
KIND Содержит строку, определяющую тип файла




ARG Содержит каждый позиционный параметр командной строки
LIST Содержит список проверяемых имен файлов




FILE Содержит имя каждого файла, который должен быть обработан в цикле while
NAME Содержит строку поиска для определения местонахождения указанных файлов
CMD Содержит команду выдачи результатов на принтер



ПОИСК ФАЙЛОВ


Этот раздел посвящен поиску файлов, где бы они ни находились, выводу на экран выбранной информации и поиску символьных строк внутри файлов.

Первая программа, tree, обходит все файловое дерево и печатает имена всех файлов в формате визуального дерева. Она рекурсивно спускается в каждый каталог и находит все его файлы, обеспечивая тем самым глобальный осмотр файловых областей и их вложенной по глубине структуры.

Другое инструментальное средство - это thead. Thead печатает несколько первых строк текстовых файлов, которые находятся в данном сегменте файлового дерева. Просматривая заголовок, т.е. первые несколько строк файла, вы можете получить достаточно информации, чтобы идентифицировать содержимое файла. При вызове thead вы можете явно задать каталог либо передать команде thead по конвейеру список полных имен файлов. Это делает команду thead фильтром - особым видом команд системы UNIX, который мы обсудим позже.

Следующее инструментальное средство - tgrep. Как следует из названия, это еще одна команда, связанная с файловым деревом, которая использует утилиту grep. Tgrep ищет символьные строки в каждом файле, который находится в данном сегменте файлового дерева. Tgrep также является фильтром, так что имена файлов можно передавать ей по конвейеру.

В нашем последнем проекте в этом разделе мы обратимся к использованию каталогов как средства "навигации". Сначала мы опишем основной алгоритм для утилиты, которая для каждого файла из заданного списка файлов проверяет, находится ли этот файл в каком-либо каталоге по указанному маршруту поиска. Затем мы построим paths - утилиту, которая дополняет функцию поиска полезными опциями.



ПОЯСНЕНИЯ


Первая строка содержит только знак двоеточия (:) - "нулевую команду". Это связано с тем, что все командные файлы, описываемые в этой книге, сделаны так, чтобы их можно было запускать в среде интерпретатора Bourne shell. Наш комментарий в строке 2, идентифицирующий версию, начинается со знака решетки (#). Си-shell ищет этот знак как первый знак командного файла. Если он найден, то предпринимается попытка выполнить данный командный файл. В противном случае Си-shell передает командный файл интерпретатору Bourne shell. Вот почему мы не хотим начинать первую строку со знака #. Мы, конечно, могли бы оставить первую строку чистой, но чистая строка невидима и может быть случайно удалена. Соответственно мы будем использовать чистые строки в других случаях, чтобы выделить важные участки программы.

Строка 2 идентифицирует версию. Символьная строка @(#) есть специальная последовательность в строке комментария, которая распознается как строка "what" ("что"). Команда what в системе UNIX читает файл и печатает сообщение, которое следует за строкой "what". Чтобы идентифицировать версию данного командного файла, наберите

# what tree и будет напечатано следующее сообщение: tree: tree v1.0 Visual display of a file tree Author: Russ Sage

Строки 4-7 проверяют, не слишком ли много аргументов было передано командной строке. Это осуществляется путем исследования переменной $#, которая представляет собой счетчик числа позиционных параметров командной строки. Если насчитывается более одного параметра, печатается соответствующее сообщение об ошибке в стандартный файл ошибок (stderr) и программа останавливается с плохим значением статуса.

Отметим, что команда echo обычно печатает в стандартный выход (stdout). Мы можем перенаправить stdout в другой файловый дескриптор, указав его. В данном случае мы собираемся печатать в stderr. Синтаксис переводится так: "вывести эту строку и перенаправить ее в файловый дескриптор (&) стандартного файла ошибок (2)". Печать сообщений об ошибках в stderr обеспечивает согласованное поведение командного файла независимо от среды, в которой он запущен.


Строки 4-8 выполняют проверку ошибок. Так как команда thead не имеет никаких опций, любые позиционные параметры, которые начинаются с дефиса (-) являются неверными. Если первым символом первого позиционного параметра оказывается "-", то печатается сообщение "argument error" (ошибка аргумента) вместе с сообщением о способе запуска и команда thead прекращает работу.

Некоторые приемы программирования для интерпретатора shell, используемые в этих строках, довольно часто встречаются в данной книге, поэтому имеет смысл остановиться на них подробнее. Проанализируем строку 4, работающую изнутри наружу. Команда echo выдает содержимое $1 (текущий параметр командной строки), которое передается по программному каналу команде cut. Команда cut используется для того, чтобы выделить определенные символы или группы символов из строки. В данном случае опция -c1 используется для получения только первого символа.




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

Строки 6-18 выполняют проверку на наличие ошибок. Проверяется, является ли первым символом каждого позиционного параметра символ "-". Если проверка успешна, то проверяется на корректность сам аргумент. Возможными опциями являются -c и -h. Если указано что-либо другое, выводится сообщение об ошибке и программа завершается. Обратите внимание, что с помощью команды shift допустимые опции удаляются из командной строки. Это сделано для того, чтобы впоследствии выражение $@ могло быть использовано для получения только аргументов строки поиска и маршрута. Выражение $@ является другой формой выражения $ *, в которой оно распространяется на все позиционные параметры. Однако в последующем тексте мы увидим одно большое отличие между ними.

Еще один трюк сделан при присвоении значения переменной OPT в строке 10. Этой переменной нам необходимо присвоить значение, которое включает в себя пару кавычек, поскольку кавычки должны быть частью строки поиска, которая в конце концов используется оператором find. Однако обнаружение второй кавычки обычно ЗАВЕРШАЕТ оператор присваивания, а мы этого в данном случае не хотим. Выходом из ситуации является использование символа \, который отменяет специальное значение следующего за ним символа. В данном случае специальное значение было бы концом строки присваивания.

Таким образом, кавычка перед звездочкой (*) в строке 10 рассматривается как часть значения переменной OPT, вместо того, чтобы завершать операцию присваивания. Следующая встреченная кавычка также должна быть сохранена в значении переменной, чтобы указать конец хранимой здесь строки поиска, поэтому она также экранирована символом \. Последняя кавычка в этой строке не экранирована обратной косой чертой. Эта кавычка соответствует своей обычной функции в смысле интерпретатора shell и завершает оператор присваивания.

Вам нужно поэкспериментировать с использованием кавычек, чтобы понять его. Когда какой-то командный файл не желает работать правильно, но ошибок не видно, проверьте правильность использования кавычек. Оставшаяся часть командного файла - это оператор case (строки 21-37), который имеет дело с числом аргументов командной строки. Если нет никаких аргументов, печатается сообщение об ошибке и мы выходим из программы. Мы ведь не можем делать никакого поиска командой grep, если мы даже не знаем, какую строку нужно искать.




В строке 4 инициализируется переменная FORMAT, указывая маршрутный тип поиска. Выполняется действие по умолчанию, точно такое же, как в командном файле path, который мы рассмотрели ранее.

В строках 6-19 все аргументы командной строки проверяются на корректность. Критерием того, что аргумент есть опция, является дефис в роли первого символа. Заметим, что здесь не разрешено использование синтаксиса "-xyz". Это заставляет вас пользоваться синтаксисом "-x -y -z". Хотя этот момент может показаться несущественным, на самом деле он важен. Всегда нужно достигать компромисса между быстрой разработкой командного файла при согласии на недостатки жесткого синтаксиса - и разрешением гибкого формата за счет дополнительных усилий по кодированию и отладке и за счет более медленного выполнения. Ваш выбор зависит от ваших приоритетов, от количества людей, использующих ваше инструментальное средство, и от того, насколько критична скорость выполнения. Конечно, если скорость критична, вы, вероятно, захотите использовать каким-то образом язык Си. Мы оставляем обработку конкатенированных опций в качестве упражнения для читателя.

Цикл for проходит по всем позиционным параметрам. Если первым символом аргумента является "-", то он сверяется со списком допустимых аргументов с помощью оператора case в строках 9-17. Опция "-l" изменяет переменную формата, после чего убирается из рассмотрения. Это делается для освобождения этой позиции, чтобы конечным результатом были просто имена файлов в командной строке.

Опция "-s" также изменяет переменную формата. Однако, вместо того, чтобы убрать опцию из командной строки, она ликвидирует всю командную строку и заменяет ее символом "l". Это заставляет цикл for проходить только одну итерацию, так как в командной строке теперь только один параметр. Благодаря такому обращению с командной строкой, нам не нужен другой цикл: мы можем использовать тот же цикл, что и в определении маршрута, без всяких модификаций. Поскольку после опции s не ожидается никаких имен файлов, мы больше не хотим рассматривать командную строку.




В строках 4-8 проверяется, является ли первым аргументом командной строки -m - опция команды more. Если эта опция найдена, то в переменную MORE заносится указание конвейера и команда more. Тем самым устанавливается постобработка, которую следует применить к выходу команды ls. Затем эта опция убирается из командной строки. Это делается для того, чтобы остаток командной строки можно было передать команде ls, не вызвав при этом нежелательных эффектов. Если первой опцией не является -m, переменной MORE присваивается нулевое значение, чтобы она впоследствии не влияла на командную строку.

Строка 10 - это командная строка, которую вы бы использовали на старой UNIX-машине типа Version 7 или System III. Она не имеет ни встроенной опции для печати символов косой черты (/) и звездочек (*), ни возможности печати в виде колонок. Вы должны пожертвовать первой возможностью, а распечатки в виде нескольких колонок можно получить с помощью команды pr системы UNIX. Команда pr использована с опцией "-5t", поэтому она печатает в пять колонок (что обычно приемлемо, но если встречаются длинные имена файлов, то пяти колонок может оказаться слишком много) и не печатает верхний и нижний колонтитулы. Благодаря отказу от колонтитулов, 24-строчный формат не слишком неудобен для вас.

Отметим, что здесь использована команда eval. Это специальная встроенная команда интерпретатора shell, которая выполняет перевычисление текущей строки, подлежащей выполнению. Интерпретатор shell повторно анализирует эту строку, чтобы раскрыть значение имен переменных в командной строке и обеспечить распознавание переменных как таковых. Здесь мы перевычисляем переменную MORE. Напомним, что мы поместили в эту переменную конвейер. Если мы не перевычислим командную строку, то команда pr попытается открыть файлы "|" и "more", которые не существуют. Для того, чтобы shell вместо этого воспринял эти символы как указания конвейеров и программ, и используется команда eval.

Строка 10 имеет еще одну особенность. В командной строке уже есть один конвейер. Откуда shell знает, трактовать ли символ "|" как имя файла или как конвейер? Благодаря тому, что аргумент команды eval заключен в кавычки. Это указывает команде eval сохранить все, что находится в кавычках, без изменений, но раскрыть значение переменной MORE и поместить его в конец командной строки, находящейся в кавычках. Несколько непонятно, но если вы думаете об этом пару лет, оно становится осмысленным.




Если первым позиционным параметром является -m, то в строке 4 инициализируется переменная MORE для подключения конвейера и программы /usr/bin/more. (Вопрос о том, почему используется абсолютное маршрутное имя, обсуждался в предыдущем разделе.) Затем символьная строка -m командой shift убирается из командной строки. Если же первой опцией не является -m, то переменная MORE устанавливается в нуль, чтобы не влиять на повторный разбор командной строки, выполняемый с помощью команды eval (строка 10).

В строке 10 команда eval использована для получения результирующей командной строки. Команда ls вызывается с опциями -al (выдача списка всех файлов в длинном формате), которые мы установили по умолчанию. Затем берутся аргументы командной строки (минус первый аргумент, если это был -m, который мы убрали командой shift). Этими аргументами могут быть дополнительные опции команды ls плюс имена файлов или каталогов. В конце строки значение переменной MORE обеспечивает конвейер с командой more, если была указана опция -m. В противном случае значение переменной MORE равно нулю и не оказывает никакого влияния на анализ содержимого командной строки.

Что произошло бы, если бы пользователь указал опцию -m в качестве второй (или последующей) опции? В этом случае опция -m передалась бы команде ls. Команда ls трактовала бы эту опцию как "потоковый вывод", а это совсем не то, что мы хотели. Однако команда ls была вызвана также с опцией -l, которая отменяет опцию -m в соответствии с текстом программы ls. Вы не получили бы вывод с помощью команды more, но ваши выходные данные по-прежнему были бы выведены в правильном формате.




Опции, которые могут быть указаны в командной строке, должны быть самым первым аргументом. Это создает более строгий синтаксис, по которому можно выловить ошибку. Но это несколько ограничивает гибкость. Как было ранее отмечено, вы можете, если хотите, по-своему разрешить компромисс между эффективностью и гибкостью путем дополнительного программирования.

В строке 4 проверяется, включены ли какие-либо параметры. Если параметры есть, то они обрабатываются. Если не используются никакие параметры, ничего не делается и управление передается на строку 27. Если были использованы какие-либо аргументы и первым символом является знак минуса (-), то выполняется оператор case для определения того, какой тип файла указан. Переменная KIND устанавливается в соответствии с типом файла, и данный параметр удаляется из командной строки командой shift. Если аргумент не совпадает ни с одной из допустимых опций, то ему соответствует случай *, что означает ошибку. На стандартное устройство регистрации ошибок выводится соответствующее сообщение об ошибке и синтаксическая подсказка, после этого kind завершается с плохим статусом выполнения.

В строке 27 производится проверка того, установлена переменная KIND или равна нулю. Если она равна нулю, в нее подставляется символьная строка "text". Если KIND уже установлена, то она не меняется. Это неплохой оператор присвоения значения по умолчанию. Таким образом, пользователь не обязан указывать опцию -t в командной строке. Если же опция -t была указана, то ей есть что сопоставить в операторе case.

Оставшаяся часть программы в строках 29-35 представляет собой еще один оператор case, который проверяет количество аргументов, оставшихся в командной строке после обработки ошибок. Если была указана какая-либо опция, то переменная KIND установлена и опция убрана командой shift. В командной строке могли остаться только аргументы, которые являются именами файлов или маршрутами. Если к тому времени, когда мы уже готовы к заключительной обработке, не осталось никаких аргументов, то значит в командной строке не было указано ни одного имени файла.

В этом случае в строках 30-33 организовывается цикл, который читает имена файлов из стандартного ввода, запускает команду file и использует команду fgrep для определения того, соответствует ли тип файла, выданный командой file, интересующему нас типу (хранимому в переменной KIND). Затем мы используем команду cut для выделения того, что нам нужно. Обычный вывод команды file содержит имя файла, двоеточие и затем описание. Нам нужно только имя файла, поэтому мы вырезаем первое поле, используя разделитель ":". Когда никакие данные больше не поступают, цикл while завершается, мы попадаем в конец оператора case и выходим из программы.

Если же аргументы НАЙДЕНЫ в командной строке, то вместо всего этого выполняется ветвь оператора case в строке 34. С помощью обозначения $@, имена всех файлов в командной строке включены в команду file. Таким образом, не нужен никакой цикл. Во всем остальном обработка идентична строке 32.




Поскольку в этом командном файле не так много текста, то все довольно понятно, нет ни обработки ошибок, ни других дополнений. Просто нехитрый вызов команды more. Полное имя здесь указано с целью повышения быстродействия, как мы обсуждали ранее. Вы должны перепроверить местонахождение вашей команды more. В системе Berkeley она может находиться в каталоге /usr/ ucb/more. Воспользуйтесь командой path more для определения этого места и вставьте соответствующий маршрут вместо указанного нами.

Кстати, фокус попадания этой символьной строки в текст вашего командного файла состоит в том, чтобы войти в редактор и вызвать следующую команду:

:.!path more

Здесь происходит переход в shell и запуск команды path (:!), затем выход команды path (который представляет собой полное маршрутное имя) помещается в буфер редактора в самом начале текущей строки (.). После этого вы имеете эти данные в вашем редактируемом файле и при необходимости можете отредактировать их.




В строке 4 проверяется, равно ли нулю количество аргументов в командной строке. Если да, в стандартный файл ошибок выдается сообщение об ошибке. Выводится также синтаксическая подсказка, и mmm завершается с плохим статусом.

Переменная LIST инициализируется нулевым значением в строке 10. Обычно переменные интерпретатора shell и так в начале равны нулю, но предварительная установка значения является хорошим стилем программирования.

Затем мы обрабатываем каждый аргумент командной строки в цикле (строки 11-17). Все аргументы должны быть именами файлов, поэтому каждый из них проверяется на то, существует ли он как обычный файл. Если это не файл, то в стандартный файл ошибок выводится сообщение об ошибке. Тем не менее программа не завершается. Не следует аварийно прекращать всю программу только потому, что нет указанного файла. Мы пропускаем его и идем до конца списка аргументов. Это особенно актуально, если данная команда используется как фоновая во время выполнения другой работы. Пользователь скорее согласится с тем, чтобы было выполнено побольше работы, чем не сделано вообще ничего. Это решение, принятое в данной программе, и вы можете изменить его, если оно не подходит в вашей ситуации.

Если имени соответствует допустимый файл, оно добавляется в список хороших имен файлов. Этот список становится главным списком для команды nroff.

После того как все аргументы проверены, мы в строке 9 строим и выполняем командную строку nroff.

Опция -rO0 для nroff указывает макросам обработки рукописей (пакету mm) установить регистр, который имеет дело с отступом текста, в состояние, соответствующее отступу в 0 символов. Это значит, что весь текст начинается с крайней левой позиции, т.е. выровнен слева. Путем проведения экспериментов я обнаружил, что левое выравнивание текста программой nroff и установка отступа для принтера дает наиболее надежный вывод на печать. В противном случае, если вы установите отступ текста в nroff и отступ в принтере, то может произойти настоящее столкновение, когда дело коснется вывода колонок в странице. Вы можете изменить это место, если ваши программы вывода или устройства печати ведут себя как-то иначе. Опция -mm указывает программе nroff просмотреть библиотеку макросов обработки рукописей, чтобы определить, используются ли какие-либо из них во входном документе. Эти макросы очень большие и требуют много времени центрального процессора. Если вам необходимо использовать их, то вам потребуется большой компьютер или компьютер, специально предназначенный для этой цели, чтобы добиться хорошего времени получения результата.

Последним аргументом является $LIST. В этой переменной находится строка имен файлов, разделенных пробелами. Эти имена помещаются в командную строку nroff. Можете быть уверенными, что в этом месте нет никаких ошибок.




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

В строке 12 инициализируется переменная NAME. Это действие выполняется по умолчанию, поэтому данная строка дает возможность не указывать опцию в командной строке. Оператор if в строке 13 означает: "Если первым символом первого аргумента является дефис", то нужно проверить, какая это опция.

Если установлена опция -t, то переменная NAME инициализируется нулевым значением, что совпадает с действием по умолчанию, поэтому на самом деле ничего не меняется. Затем эта опция удаляется из командной строки.

Если установлена опция -d, то переменная NAME инициализируется для поиска символьной строки, соответствующей именам файлов программной разработки. Обратите внимание, что двойные кавычки внутри оператора экранированы, т.е. впереди них стоят символы наклонной черты. Командный интерпретатор shell воспринимает кавычки вокруг строки поиска на первой фазе синтаксического разбора без отмены присвоения, тем самым оставляя двойные кавычки последующей команде find.

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

В строке 27 выводится сообщение о том, какой файл содержит результаты работы. Сам этот оператор не создает файл. Он только печатает имя файла, который будет создан позже.

Строки 29-43 - это главный цикл всей программы. Оператор find должен быть повторно проанализирован командой eval, поскольку переменная NAME содержит нужные нам данные. Если бы не было команды eval, то подстановка символьных строк выполнялась бы неправильно. Обратите внимание, что переменной NAME не требуются кавычки в строке 24. Они уже есть в переменной NAME, так как были обработаны командой eval.

Оператор find находит только файлы типа f, или обычные файлы, т.е. не каталоги и не символьные или блочные устройства. Здесь под "обычными файлами" понимается, что они еще могут быть файлами данных или исполняемыми. Если значение переменной NAME равно нулю, оно не влияет на командную строку. Если NAME содержит символы файлов программной разработки, то они становятся частью команды find при выполнении команды eval. Это накладывает ограничения на шаблон поиска команды find. Когда файлы найдены, их имена выводятся в стандартный вывод.



ПРИМЕР ВЫЗОВА


$ tree $HOME

Выводит структуру файлового дерева регистрационного каталога.


$ find $HOME/src -name "*.c" -print | sort | thead

Печатает заголовки ( первые несколько строк) всех моих исходных файлов на языке Си.


# tgrep "profanity" /
Поиск слова "profanity" по всей системе ( суперпользователь снова на тропе войны!)


$ paths -l ed ex vi
Выдает в длинном формате имена файлов, которые являются исполняемыми модулями редакторов ed, ex и vi


lc -R $HOME
Выдает список всех файлов во всех подкаталогах моего регистрационного каталога.


ll *.c Выдача списка файлов с исходными текстами на языке Си в длинном формате.


more `kind /etc/*`
Вывод командой more всех текстовых файлов, имеющихся в каталоге /etc.


m * Вывод командой more всех файлов текущего каталога


mmm memo Обработать с помощью nroff файл моих заметок memo и отобразить его на экран

текущий каталог, что равносильно команде


1. $ tree
Использует подразумеваемый каталог ( текущий каталог, что равносильно команде "$ tree .") в качестве начала файлового дерева.
2. $ tree /

Печатает древовидный листинг для КАЖДОГО файла всей системы. Команда find при таком ее запуске начинает с корневого каталога и выдает информацию о всех файлах системы.
3. $ tree $HOME/..
Показывает древовидный формат для всех других пользователей системы (предполагается, что все пользовательские каталоги находятся в одном и том же каталоге, например /usr/*).


1. $ thead /etc
Печатает данные из каждого текстового файла, находящегося в каталоге /etc. Очень полезная команда, так как большинство файлов в /etc являются исполняемыми модулями. Удобно иметь возможность быстро изолировать текстовые файлы.
2. $ thead /usr/include
Просматривает все подключаемые файлы (*.h), даже в системном подкаталоге sys.
3. $ find $HOME -ctime 0 -print | thead

Ищет все файлы в вашем регистрационном каталоге, которые были изменены в течении последних 24 часов. Для каждого файла проверяется, текстовый ли он. Если файл текстовый, то он печатается.


1. $ tgrep unix $HOME
Поиск любого вхождения слова unix во всех файлах моего регистрационного каталога.

2. $ tgrep -c "^sleep()$" $HOME/src
Поиск выражения (начало строки, символьная строка, конец строки) во всех исходных файлах на языке Си в регистрационном каталоге с исходными текстами (опция -c).
3. # find /usr/src -name "*.c" -print | tgrep "ioctl"
Поиск всех вызовов ioctl в исходных Си-файлах, начиная с каталога /usr/src. (Обратите внимание, что я являюсь суперпользователем. Это видно из того, что я занимаюсь поиском в ограниченной части системы, а именно в исходных дистрибутивах, а также из того, что в качестве символа приглашения используется символ "#".)
4. $ tgrep "| more" `find . -type f -print`
Поиск символа вертикальной черты (|), после которого следует слово more, в списке имен файлов, генерируемом оператором find. Find печатает имена всех файлов текущего каталога и всех подкаталогов, которые являются обычными файлами.
5. $ tgrep trap /bin /usr/bin /etc
Поиск команды прерывания (trap) во всех командных файлах интерпретатора shell, которые имеются в трех каталогах.


1. $ paths ls more who paths /bin/ls /usr/bin/more /bin/who /usr/russ/bin/paths
Поиск маршрутов к командам ls, more, who, paths. При выводе указываются полные абсолютные маршрутные имена. Обратите внимание, что в конце имени каждого файла печатается символ новой строки, чтобы получить распечатку, в которой каждое имя файла стоит в отдельной строке.
2. $ more `paths gettydefs termcap paths`
Если ваша переменная PATH содержит каталог /etc, то этот пример будет работать. Если нет, то первые два файла не будут найдены. Сначала запускается команда paths, и ее вывод помещается на свое место в командной строке команды more. Когда запускается команда more, она не знает, что ее аргументы получены от другой команды. После завершения работы команды paths команда more принимает вид:
more /etc/gettydefs /etc/termcap/usr/russ/bin/paths
с полными маршрутными именами каждого файла. Этот пример показывает, как можно заставить команду paths выполнять всю работу по поиску и показу файлов, которые вы хотите увидеть.
3. $ ll `paths ll`
В этом примере в длинном формате выводятся файлы с именами ll, которые найдет path. (Мы представим нашу версию команды ll несколько позже в этой же главе.) Как и в предыдущем случае, сначала генерируется информация о маршруте, затем она помещается в командную строку, а затем запускается команда ll.
4. $ m `paths paths`
В данном примере генерируется маршрутное имя самого командного файла paths и передается программе m, которая использует команду more для распечатки. (Командный файл m мы также покажем вам позже.)


1. $ lc `path lc`
Получает полное имя для lc и распечатывает файловую информацию в виде колонок.
2. $ lc -m -R /
Печатает колоночный список ВСЕХ файлов в системе, рекурсивно проходя вниз по иерархии системного дерева и пропуская распечатку через команду more.
Еще один маленький фокус: этот синтаксис был использован для создания другой команды, названной expose. Командная строка "lc -m -R $@" давала бы рекурсивный список всех файлов в любом каталоге по вашему выбору в приятном постраничном формате.
3. $ lc -m -R /usr/lib
Рекурсивно распечатывает список всех файлов во всех каталогах, начиная с /usr/lib, и пропускает листинг через команду more.
4. $ lc -m . | more
Выдает список файлов в текущем каталоге и пропускает листинг через команду more, а затем снова пропускает все через more. Работает ли это ? Никоим образом. Возникает полная путаница, и клавиша прерывания обычно является наилучшим способом выхода из данной ситуации.


1. $ ll /etc/*mount*
Выводит список всех файлов в каталоге /etc, имена которых содержат в каком-либо месте слово mount (например, mount, umount, unmountable).
2. $ ll -i `who|awk '{print "/dev/" $2}'`
Сперва выполняется команда who, затем результат ее работы по конвейеру передается команде awk, которая вырезает имя устройства и приписывает ему префикс /dev/. В результате список полных маршрутных имен ко всем терминальным устройствам, зарегистрированным в настоящий момент, помещается в командную строку команды ls -li. В распечатке указана вся информация об индексном дескрипторе файла (inode) для каждого терминального устройства.
3. $ ll `kind -a /lib`
Выводит в длинном формате список всех файлов архива в каталоге /lib. Этот каталог содержит библиотеки компиляторов всех языков системы UNIX. (Команда kind, которая отбирает файлы по их типу, рассматривается в следующем разделе.)
4. $ ll -m -i /dev
Выводит всю обычную информацию плюс номер индексного дескриптора для всех файлов в каталоге /dev. Выдача на экран происходит с помощью команды more.


1. $ od `kind -d /etc/*`
Выглядит так, как будто это должно работать, но команда od не работает с набором имен файлов. Она может обрабатывать только один файл в данный момент времени.
2. $ ll `sh -x kind -a /lib/*` | m
Это длинный пример. Выводит в длинном формате список всех файлов архивов, которые находятся в каталоге /lib. Мы запускаем shell в отладочном режиме выполнения, так что вы можете увидеть каждую командную строку перед ее выполнением. Результат по конвейеру передается команде more.
3. # find / -print | kind -x | while read FILE > do > ll $FILE > done > /tmp/filelist
Данный цикл обнаруживает все действительно исполняемые файлы. Для каждого из них выполняется команда "ls -l". Отметим, что здесь команда ll вызывается для каждого имени файла.
Вы могли бы выполнить ту же операцию при помощи такого оператора find:
find / -perm -0111 -exec ll {} \;
но опция perm в данном случае опять же проверяет биты прав доступа в индексном дескрипторе файла, а не ищет магическое число в структуре a.out, как описано ранее. Кстати, для того, чтобы вы могли успешно запустить команду file (и тем самым kind) на системных файлах, вы должны иметь права чтения, чтобы можно было прочитать магическое число.
4. $ for F in `kind /bin/* /usr/bin/* /etc/*` > do > fgrep "trap" $F /dev/null > done $ fgrep "trap" `kind /bin/* /usr/bin/* /etc/*`
$ find /bin /usr/bin/etc -exec fgrep "trap" {} \;
Это три различных способа поиска слова "trap" во всех текстовых файлах.


1. $ ll -R / | m
Начиная с корневого каталога (/), вывести в длинном формате (ll) все файлы (опция -a подразумевается в ll) всей системы (-R) и постранично распечатать на экран (| m).
2. $ m `path inittab rc passwd`
Обнаружить и вывести с помощью more системные файлы inittab, rc и passwd. Неприятность здесь заключается в том, что данный маршрут скорее всего относится к каталогу /bin/passwd, а не /etc/passwd (поскольку каталог /etc размещается в конце каталогов), а это означает, что вы можете попытаться вывести на экран исполняемый файл. В зависимости от того, какую из версий команды more вы запустили, это может привести к чему угодно начиная с сообщения команды more о том, что это был не текстовый файл, и заканчивая тем, что ваш терминал начнет показывать непонятные символы и даже зависнет.


1. $ mmm nroffile | m
Запуск команды nroff применительно к файлу nroffile, вывод результата на экран с передачей по конвейеру команде more. Это полезно при изучении утилиты nroff, проведении экспериментов с различными командами и наблюдения за соответствующими результатами.
2. $ for F in proj.? do mmm $F > $F.rf done
Обработка в цикле всех файлов, имена которых содержат символьную строку "proj.", за которой следует один символ. Это могут быть proj.1, proj.2 и так далее по всему набору символов вплоть до proj.z, proj.{, proj.|, proj.} и proj.~, если считать, что у вас есть файлы, имена которых содержат эти символы. Каждый файл обрабатывается, и выход nroff перенаправляется в файл с таким же именем, дополненным символами .rf.
3. $ mmm status[12] | lpr -o5
Обработка командой nroff файлов status1 и status2. Выход в стандартный вывод передается по конвейеру программе lpr. Программа lpr является фильтром и принимает или имена файлов в командной строке, или непосредственно данные, передаваемые ей по конвейеру (но не то и другое сразу). Опция -o5 указывает lpr сместить страницу на 5 символов.


1. $ pall /usr/include
Выводит ВСЕ файлы заголовков. Сюда включаются файлы заголовков в подкаталоге sys и во всех других каталогах, которые могут располагаться ниже каталога /usr/include. Это и есть причина, по которой был написан командный файл pall. Он создает один огромный листинг всех файлов заголовков в отсортированном порядке с печатью в заголовке страниц полного имени.
2. $ pall $HOME/src
Обходит все каталоги, находящиеся ниже каталога исходных текстов, и распечатывает все файлы.

РАСПЕЧАТКА ФАЙЛОВОЙ ИНФОРМАЦИИ


Этот раздел знакомит вас с инструментальными средствами, предназначенными для вывода на экран имен файлов и их содержимого. Инструменты такого рода весьма полезны, так как они могут значительно уменьшить количество необходимых символов, набираемых с клавиатуры при запуске команды, и внести больше смысла в одну команду.

Первые два командных файла являются пре- и постпроцессорами для команды ls. Команда lc выводит файловую информацию по столбцам, команда ll перечисляет файлы в длинном формате. Эти командные файлы дополнены опциями команды ls, чтобы сделать распечатки более информативными. Так как команда ls используется довольно часто, упаковка наиболее часто применяемых нажатий клавиш в командные файлы представляется целесообразной. Упаковка уменьшает количество постоянно набираемых символов и упрощает использование команд, исключает необходимость запоминания подробного синтаксиса.

Третье инструментальное средство - это kind. Kind - еще один командный файл препроцессорного типа, использующий команду UNIX file. Команда file читает указанный файл и затем сообщает, является ли этот файл текстовым, архивным или исполняемым. Поскольку распечатки команды file не выбирают файлы заданного типа, возникает необходимость в создании для этого специальной утилиты. Команда kind работает с распечаткой команды file. Kind выводит на экран имена файлов только заданного типа.

Еще один командный файл - m, который облегчает работу со стандартной командой more системы UNIX, уменьшая количество необходимых для запуска команды символов и упрощая интерфейс. Делается это без потери гибкости: так же, как вы можете использовать команду more для файла или передать команде more данные по программному каналу, вы можете сделать то же самое для m.

Следующий командный файл - это mmm. Он состоит из одной заготовленной командной строки для программы nroff системы UNIX. Существует много способов вызова команды nroff и множество различных опций к ней. Если же вы редко используете nroff, у вас могут возникнуть трудности в запоминании специфических опций, необходимых для вашей работы с командой. Эти проблемы отпадут, если у вас есть команда mmm. Определите опции, которые вы обычно используете, и введите их в командный файл mmm (о том, как это сделать практически, речь пойдет ниже). Теперь достаточно набрать mmm - и вы имеете возможность работать с вашей командой nroff.

Последняя утилита - pall. Pall обходит файловое дерево, ведя поиск файлов заданного типа, и готовит их к выводу на принтер. Команда pr системы UNIX используется для разбивки на страницы всех файлов вместе и включения заголовков. Эта команда предлагает на рассмотрение принтеру один большой файл и наиболее полезна в тех случаях, когда у вас имеется множество каталогов с текстовыми файлами или с исходными файлами программ.

Определив в общем основные наши задачи, перейдем к более близкому знакомству с упомянутыми инструментальными средствами.



ТЕКСТ ПРОГРАММЫ


1 : 2 # @(#) tree v1.0 Visual display of a file tree Author: Russ Sage 2а вывод на экран структуры файлового дерева

4 if [ "$#" -gt 1 ] 5 then echo "tree: wrong arg count">&2 6 echo "usage: tree [dir]" >&2 7 exit 2 8 fi 9 if [ "$#" -eq 1 ] 10 then if [ ! -d $1 ] 11 then echo "$0: $1 not a directory">&2 12 echo "usage: tree [dir]" >&2 13 exit 2 14 fi 15 fi

17 find ${1:-.} -print | sort | sed -e "1p" -e "1d" \ 18 -e "s|[^/]*/| /|g" \ 19 -e "s|[^ */|/|" \ 20 -e "s|/\([^/]*\)$|\1|"


1 : 2 # @(#) thead v1.0 Prints head of files in tree Author: Russ Sage 2а Печатает заголовки файлов в дереве

4 if [ "`echo $1|cut -c1`" = "-" ] 5 then echo "$0: arg error" 6 echo "usage: $0 [dir ...]" 7 exit 1 8 fi

10 case $# in 11 0) while read FILE 12 do 13 if file $FILE | fgrep text >/dev/null 2>&1 14 then echo "\n:::::::::::::::::::::" 15 echo " $FILE" 16 echo "\n:::::::::::::::::::::" 17 head -15 $FILE 18 fi 19 done;; 20 *) for NAME in $* 21 do 22 find $NAME -type f -print | sort | wile read FILE 23 do 24 if file $FILE | fgrep text >/dev/null 2>&1 25 then echo "\n:::::::::::::::::::::" 26 echo " $FILE" 27 echo "\n:::::::::::::::::::::" 28 head -15 $FILE 29 fi 30 done 31 done;; 32 esac




1 : 2 # @(#) tgrep v1.0 Search for string in tree Author: Russ Sage 2а Поиск строки в дереве

4 OPT=""

6 for ARG in $@ 7 do 8 if [ "`echo $ARG|cut -c1`" = "-" ] 9 then case $ARG in 10 -c) OPT="-name \"*.c\"" 11 shift;; 12 -h) OPT="-name \"*.h\"" 13 shift;; 14 *) echo "$O: incorrect argument" >&2 15 echo "usage: $O [-c|-h] string [file ...] >&2 16 exit 1;; 17 esac 18 fi 19 done

21 case $# in 22 0) echo "$O: argument error" >&2 23 echo "usage: $O [-c|-h] string [dir ...]" >&2 24 exit 2 25 ;; 26 1) while read FILE 27 do 28 grep -y "$1" $FILE /dev/nul 29 done 30 ;; 31 *) STRING=$1; shift 32 eval find "$@" -type f $OPT -print | sort | while read FILE 33 do 34 grep -y "$STRING" $FILE /dev/null 35 done 36 ;; 37 esac




1 : 2 # @(#) paths v1.0 Path locator with special options Author: Russ Sage 2а Определитель местонахождения файлов со специальными опциями

4 FORMAT="path"

6 for ARG in $@ 7 do 8 if [ '`echo $ARG | cut -c1`" = "-" ] 9 then case $ARG in 10 -l) FORMAT="ls" 11 shift;; 12 -s) FORMAT="set" 13 set "1";; 14 *) echo $0: arg error" >&2 15 echo "usage: $0 [-l] [-s] file [file ...]" >&2 16 exit 1;; 17 esac 18 fi 19 done

21 IFS="${IFS}:"

23 for FILE in $@ 24 do 25 for DIR in $PATH 26 do 27 case $FORMAT in 28 path) if [ -f $DIR/$FILE ] 29 then echo $DIR/$FILE 30 fi;; 31 ls) if [ -f $DIR/$FILE ] 32 then ls -l $DIR/$FILE 33 fi;; 34 set) echo "\n:::::::::::::::::::" 35 echo "$DIR" 36 echo "::::::::::::::::::::" 37 ls -al $DIR | grep "^[^ ]*s[^ ]*";; 38 esac 39 done 40 done




1 : 2 # @(#) lc v1.0 List files in a column Author: Russ Sage 2а Выводит список файлов в колоночном виде

4 if [ "$1" = "-m" ] 5 then MORE="| /usr/bin/more" 6 shift 7 else MORE="" 8 fi

10 eval "/bin/ls -a $@ | /bin/pr -5t" $MORE # pre System V 11 eval /bin/ls -aCF $@ $MORE # System V




1 : 2 # @(#) ll v1.0 Long listing of files Author: Russ Sage 2а Выводит список файлов в длинном формате

4 if [ "$1" = "-m" ] 5 then MORE="| /usr/bin/more" 6 shift 7 else MORE="" 8 fi

10 eval /bin/ls -al $@ MORE




1 : 2 # @(#) kind v1.0 Prints files of the same kind Author: Russ Sage 2а Выводит список файлов определенного вида

4 if [ $# -gt 0 ] 5 then if [ `echo $1 | cut -c1` = "-" ] 6 then case #1 in 7 -a) KIND='archive' 8 shift;; 9 -d) KIND='data' 10 shift;; 11 -t) KIND='text' 12 shift;; 13 -x) KIND='executable' 14 shift;; 15 *) echo "kind: arg error" >&2 16 echo "usage: kind [-a] [-d] [-t] [-x] [file...]" >&2 17 echo " -a archive" >&2 18 echo " -d data" >&2 19 echo " -t text, default" >&2 20 echo " -x executable" >&2 21 echo " if no args, reads stdin" >&2 22 exit 1;; 23 esac 24 fi 25 fi

27 : ${KIND:='text'} 29 case $# in 30 0) while read FILE 31 do 32 file $FILE | fgrep $KIND | cut -d: -f1 33 done;; 34 *) file $@ | fgrep $KIND | cut -d: -f1;; 35 esac



Tgrep - поиск строк в дереве файловой системы


ИМЯ: tgrep

tgrep Поиск строки по шаблону в дереве файлов



Thead - печать начала каждого файла


ИМЯ: thead

thеаd Печатает заголовок (первые несколько строк) файлов.



Tree - визуализация файлового дерева


ИМЯ: TREE

tree - вывод на экран структуры файлового дерева



УПРАВЛЕНИЕ ВЫВОДНЫМИ ФАЙЛАМИ БОЛЬШИХ РАЗМЕРОВ


Как мы уже отмечали, общий размер выводного файла ограничен. Напомним, что команда find проходит все дерево каталогов вниз до конца по всем поддеревьям, начиная с каталога, имя которого указано в командной строке. Если вы находитесь на вершине очень глубокого дерева, то обрабатываться могут буквально сотни файлов. Поскольку вы ограничены максимальным размером выводного файла, вы можете обработать только ограниченное число файлов. Конечно, количество файлов, которое вы можете обработать, зависит также от того, насколько велики входные файлы.

Если выводной файл достигает своего максимума, все добавляемые после этого данные теряются. Потеря данных весьма болезненна, и обычно требуется некоторое время, чтобы ее обнаружить. В медленно работающей системе попытка обработать большое дерево, например все исходные тексты системы UNIX, может занять целый час и даже больше, прежде чем выходной файл заполнится. Это означает, что вы должны находиться рядом и следить за тем, когда файл переполнится. Если он все-таки переполнился, вы должны все выбросить и начать сначала. Это также означает, что вы должны перейти вниз по дереву. Это может быть проблемой в сбалансированных деревьях.

Например, рассмотрим каталог /usr/lib. Этот каталог содержит много файлов на первом уровне и много каталогов первого уровня. Если бы мы не обработали все файлы каталога /usr/lib за одну попытку, мы должны были бы пойти вниз по подкаталогам каталога /usr/lib. Попытки делать это вручную и запускать pall в каждом подкаталоге заняли бы много времени и могли бы привести к ошибкам с вашей стороны. Кроме того, pall допускает указание только одного имени каталога, что приведет к получению большого количества распечаток и к путанице при их сортировке.

Что же делать? Радикальным решением является увеличение значения ulimit. Вы можете сделать это либо с помощью программы на языке Си, использующей системный вызов ulimit, либо командой shell'а ulimit. Техника выполнения такой работы представлена в .



ВОЗМОЖНЫЕ ИССЛЕДОВАНИЯ


В чем отличие между двумя следующими операторами?

$ find $HOME -name "*.c" -print | thead и $ find $HOME -name "*.c" -exec head {} \;

Они выглядят очень похоже, и они действительно похожи. Они обрабатывают одни и те же файлы и печатают одни и те же данные из каждого файла. Основное отличие в том, что строка, которая использует thead, печатает хорошее оформление вокруг имени файла, а чистая команда find печатает непрерывный поток текста так, что очень трудно определить, какой файл вы просматриваете.


В чем разница между двумя следующими операторами?

grep "$1" `find "$2" -print` и find "$2" -print | while read F do grep "$1" $F done

Они кажутся совершенно похожими, но существует различие в главном. Первый оператор - это один вызов команды grep. Аргументами являются множество имен файлов, поставляемых командой find. Если find сгенерирует слишком много имен файлов, то выполнение команды завершится. О том, что сгенерировано слишком много имен файлов, никакого предупреждения не выдается, но большое количество файлов фатально для grep. Поэтому мы должны рассматривать такой синтаксис как недопустимый в общем случае.

Второй оператор - это цикл. Он работает медленнее и вызывает grep много раз, что забирает много времени центрального процессора. Однако положительным моментом является то, что цикл получает данные по конвейеру, который фактически не имеет ограничений на число данных, которое он может иметь. Наша программа никогда неожиданно не прекратит выполнение.



ВОЗМОЖНЫЕ МОДИФИКАЦИИ


Для увеличения гибкости хорошо бы добавить опции, чтобы вы могли переходить на команду find непосредственно из thead. Полезными аргументами были бы -name для изолирования образцов имен файлов и -ctime для обработки изменений, связанных со временем.

Еще одной привлекательной особенностью было бы добавление опции грамматического разбора (основанной на -) и опции -n, указывающей, что из команды head должно быть напечатано n строк.


Данный командный файл открыт для многих различных видов модификации. Поиск полного имени файла является фундаментальной задачей программного обеспечения по сопровождению файлов. Эта возможность позволяет нам полагаться на саму программу paths или использовать paths в качестве куска более объемной программы.

При разработке ваших собственных программ следует обратить внимание на гибкость командного файла paths, которая выражается в отличии между обрабатываемыми форматами. Первые два формата используют отдельные файлы, а формат set использует каталоги. Дальнейшие дополнения к командному файлу paths могут касаться любой из этих строк или могут комбинировать их. Если есть необходимость, программное обеспечение может приспособиться к этому.




Было бы неплохо, если бы командный файл kind мог работать одновременно с разными типами файлов. Это означает наличие несколько опций в командной строке, например -a и -d. Вам могла бы понадобиться составная строка, в которой каждая часть была бы отделена символом |. Затем эта строка могла бы быть использована в команде egrep, например, "egrep 'archive|data'". Вам пришлось бы организовать цикл по командной строке вместо использования фиксированных позиций и убедиться в том, что вы не получите зациклившийся конвейер, когда задана только одна опция.




Поскольку все аргументы рассматриваются как имена файлов, то у нас нет способа передачи дополнительных команд пакету mm. Наличие такой возможности было бы желательным, поскольку при экспериментировании с командой nroff вам необходимо пробовать различные опции, чтобы увидеть, как они действуют. Было бы тяжелой работой выполнять редактирование текста mmm, чтобы добавить одноразовые опции, которые могут вам никогда не понадобиться или опции, которые вы должны постоянно менять.

Один из путей достижения большей гибкости - посмотреть, имеет ли какой-либо аргумент дефис в качестве первого символа. Если да, перехватить эту опцию и убрать ее из списка имен файлов. После этого вы бы имели список опций, которые нужно включить в командную строку, и список имен файлов, подлежащих обработке.

Отметим, что место, занятое в нашем командном файле указанием пакета mm, можно вместо этого заполнить ссылкой на другие макропакеты, имеющиеся в вашей системе, например -ms или -me, в зависимости от нужного вам формата. Отказ от поиска макросов, которые вам не нужны, ускорит обработку: подробности вы найдете в документации по nroff или troff.




Возможно, вы захотите добавить свои собственные штрихи в некоторых местах командного файла. Первым местом является то, где указываются символы поиска файлов программной разработки. Символы, использованные нами - это наиболее употребимые суффиксы в UNIX. Если вы используете не Си и ассемблер, а другие языки, то вы можете добавить соответствующие символы.

Следующим местом, где могут быть сделаны дополнения, являются опции, которые может понимать pall. Вам могут понадобиться файлы с определенными именами или определенными типами, например, файлы nroff. Эти опции могут быть легко добавлены в оператор case, что улучшит команду.

Последним местом возможных изменений является тип файлов, которые нужно пропускать. Символьная строка для команды egrep покрывает большинство важных нетекстовых типов файлов. В вашей системе могут быть какие-то особые типы или же имена могут быть другими. Если вам необходимо дополнить строку, сделайте это. Команда egrep может обработать довольно много информации. Я не знаю ее ограничений. Возможно, вы обнаружите их, просматривая исходный текст утилиты egrep. Если получается слишком длинная строка и не помещается на экране, ничего страшного. Перенос на следующие строки экрана не опасен, пока общее количество символов не превысит 255. Опасно только указывать переадресацию символьной строки if на нулевое устройство в следующей после команды egrep строке. Кажется, что все работает правильно, но это не так. Переадресация должна указываться в той же строке, где стоит команда egrep.

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



В был представлен обзор общей


В был представлен обзор общей структуры системы UNIX и показано, как взаимодействуют ее различные части. Это похоже на введение в географию, когда на глобусе показывают континенты и крупные водные пространства. Такая информация, хотя и является хорошим фундаментом для общих знаний, вряд ли поможет найти наилучший путь из Сан-Франциско в Лос-Анжелес. Необходим следующий уровень детализации: названия поселений, дорог, развилок, улиц, адресов.
Файловая система UNIX похожа на континент со множеством городов и, действительно, с адресами внутри городов. Каталоги и различные уровни подкаталогов можно сравнить с маршрутами между различными пунктами назначения, названия файлов - с адресами. Большое число путей и мест назначения может выглядеть пугающе, но благодаря регулярности и логичности, файловая система UNIX позволяет вам легко перемещаться из одного места в другое, если вы знаете несколько основополагающих принципов.
Будучи пользователями UNIX, все мы научились пользоваться основными командами файловой информации, как, например, ls с различными опциями. Мы знаем, как перемещаться между каталогами и копировать или перемещать файлы. Тем не менее, находить нужную информацию о файлах из всей массы информации не так-то легко. Нам необходимо создать инструментальные средства, которые используют древовидную структуру файлов в UNIX, чтобы находить то, что мы ищем, и, соответственно, выводить информацию о файлах на экран, печатать листинги содержимого файлов и т.д.
Эта глава знакомит с инструментальными средствами, которые облегчают задачу поиска и доступа к файлам. Доступ к файлам может быть обеспечен различными способами, поэтому техника и стиль меняются от одного командного файла к другому. Например, в некоторых случаях вам нужно найти имена всех файлов в данном сегменте файлового дерева, в других случаях вас будут интересовать файлы только заданного типа: текстовые файлы вообще или исходные файлы на языке Си в частности.