Я прохожу курс "Операционная система Unix" и после тестов, вижу в отчете, что этот тест сдало еще 25 человек. Почему так мало, это ведь реально хороший и полезный урок. Здесь естьи теория и практичесские материалы. Сам курс написан хорошо, живым языком. И здесь я получил ответы на вопросы по Linux, которые боялся спросить. Наверное это из-за того, что в названии курса написано не Linux, а Unix и это многих отпугивает. |
Shell как язык программирования и интегратор
И швец, и жнец
Любой универсальной ОС приходится много возиться с пользовательскими и своими собственными задачами. Лишь небольшая часть этой деятельности может быть запрограммирована раз и навсегда в ядре. Большая часть логики управления задачами и самой системой должна быть доступна администратору в виде проекта, иначе он просто не сможет ни понять происходящее в системе, ни тем более изменять ее. Стоит повнимательнее взглянуть на инструмент, используемый в UNIX для задания алгоритма работы многих частей системы, - на командный интерпретатор, shell. Оказывается, shell отлично себя показывает не только в диалоге с пользователем, но и как исполнитель сценариев, и как средство организации взаимодействия между задачами в системе.
Начнем с того, что shell - полноценный язык программирования, причем, как многие интерпретаторы, довольно высокого уровня. Если задача - разовая (нет требований по быстродействию, совместимости и переносимости) и достаточно абстрактная (нет привязки к конкретной сложной структуре данных), ее скорее всего можно решить, написав командный сценарий - программу на shell.
С другой стороны, одной алгоритмической полнотой при решении задач в системе ограничиваться нельзя. Скажем, машина Тьюринга [ 9 ] чрезвычайно проста и алгоритмически полна, однако мало кому придет в голову организовывать на основе ее модели диалог с пользователем или управление самой ОС. Здесь следует вспомнить, что shell - еще и исполнитель команд: он запросто общается с UNIX и утилитами. Значит, дополнив его механизмом управляемого взаимодействия команд с системой и друг с другом, мы получим неплохой интегратор (или оболочку - что, собственно, и есть перевод слова shell ).
Самое приятное, что такая программируемая оболочка не будет слишком выходить за рамки У: если уж, в наследство от диалоговой ипостаси shell, мы можем легко обращаться за решением подзадачи к любой утилите UNIX, дублировать ее в языке совершенно незачем, и там останутся как раз одни только алгоритмические и координационные абстракции.
Сценарий
Прежде чем рассмотреть возможности shell под двумя углами зрения, разрешим вот какое затруднение. Допустим, мы написали программу на языке какого-нибудь интерпретатора, например /bin/sh, и записали ее в некий файл, например /home/george/myscript (если /home/george - текущий каталог, можно использовать более короткий путь: myscript ). Как теперь выполнить этот сценарий? Из man sh мы знаем, что для этого можно запустить командный интерпретатор с параметром - именем файла:
$ cat myscript echo "Hello, George!" $ /bin/sh myscript Hello, George!
Нельзя ли обойтись без имени программы, которая интерпретирует сценарий? Вообще говоря, нет: в UNIX немало различных интерпретаторов с разнообразным синтаксисом, например обработчик текстов awk, потоковый текстовый редактор sed, универсальные языки программирования python и perl и много чего еще. Во всех этих языках есть возможность вставлять в текст сценария строчные комментарии, которые начинаются с символа "#" и заканчиваются в конце строки. Поэтому, если сценарий начинается с символов " #!", любой из этих интерпретаторов проигнорирует всю первую строку как комментарий. Система же, увидев " #!" в начале файла, понимает, что это сценарий. С третьего символа и до конца строки она читает имя программы, которой отдает этот файл на выполнение. Значит, если первой строкой в /home/george/myscript будет #!/bin/sh, его смело можно делать исполняемым (установить бит использования) и запускать:
$ chmod +x myscript $ cat myscript #!/bin/sh echo "Hello, $1!" $ ./myscript George Hello, George!
Строго говоря, после " #!" может стоять что угодно, например имя написанной нами программы с некоторыми обязательными параметрами; UNIX ее запустит и передаст ей в качестве параметров командной строки обязательные параметры (если они есть), затем имя сценария и все, что идет следом (в нашем примере George ). Если же после " #!" будет стоять несуществующий файл, система выдаст сообщение об ошибке:
$ cat myscript #!/bad/sh echo "Hello, $1!" $ ./myscript ./myscript: not found
Обратите, пожалуйста, внимание на то, что из этого сообщения якобы следует, что не найден сам файл сценария. Если не знать подоплеку явления, ситуация кажется подозрительной. Дело в том, что, запуская любую программу, UNIX всегда передает ей один параметр (который имеет индекс 0) - имя этой программы. Но в случае запуска сценария обработчик получит в качестве нулевого параметра не собственное имя, а имя сценария. А когда система этого обработчика не найдет, в сообщении об ошибке он будет упоминаться под новым именем.
Гнезда shell`ов
И еще одно немаловажное замечание. Сначала в UNIX был только один командный интерпретатор, написанный Стивеном Борном (Stephen Bourne), и назывался он просто "оболочка" (т. е. shell, а имя утилиты, для краткости, sh). Это была очень простая маленькая программа, она отлично работала именно как системный интегратор, но во всех остальных ипостасях была довольно слабой. И вот создателям 3BSD пришло в голову, что нужен совершенно новый командный интерпретатор, более удобный при работе в командной строке, с новыми возможностями программирования и с новым синтаксисом, приближенным к языку Си, который и так знаком любому UNIX-программисту. Получившуюся оболочку назвали C shell (за синтаксис команд; имя утилиты - csh), она была намного мощнее старой, там была работа с историей, достраивание имен файлов, управление заданиями; появились массивы и много чего еще.
Однако программировать командные сценарии на csh оказалось... менее удобно, чем на sh. Во-первых, синтаксис языка Си в точности воспроизвести не удалось, возникла путаница; во-вторых, многие системные сценарии уже были к тому времени написаны на shell. Обе эти оболочки дали начало так называемым гнездам - Bourne и C, потому что всякий новый командный интерпретатор проектировался с расчетом на совместимость либо с sh, либо с csh.
Долгое время бытовало мнение, что работать лучше в csh, а сценарии писать - на sh, хотя совмещать два разных языка в одной области деятельности неудобно. С тех пор было создано немало других, еще более мощных sh - и csh -образных оболочек. Они все время дорабатывались, попеременно обгоняя друг друга по охвату возможностей. Пальма первенства принадлежала то bash (Bourne-again shell, детище GNU), то tcsh (международный открытый проект, развивающий csh ), то zsh (также международный открытый проект, но с sh -совместимостью). На сегодня нельзя с уверенностью сказать, какой из них мощнее (хотя документации по zsh больше, чем по bash и tcsh, вместе взятых, раза в два), но устаревшее мнение о sh и csh стоит пересмотреть: теперь в какой оболочке работаешь, на языке той и сценарии пиши.