Глава 15. Принципы сборки и установки пакетов

Введение в POSIX'ивизм
(C) Алексей Федорчук, 2005

Назад Содержание Вперед

Глава 15. О шеллах

Жизнь дает человеку три радости -
дружбу, любовь и работу...
Братья Стругацкие

Перефразируя классиков советской фантастики, можно сказать, что жизнь дает POSIX'ивисту три радости: дружественный шелл, любимый текстовый редактор и много, очень много приложений для работы. Без любой из первых двух радостей прожить можно. Но это значит, что радостей будет одной меньше. А ведь их всего три. Так что эту главу я посвящаю первой из радостей - шеллам. Тем более, что это еще и первое приложение, с которым сталкивается пользователь после авторизации в системе.

Содержание

О шеллах вообще

Шелл (Shell), именуемый по-русски командной оболочкой, командным интерпретатором, командным процессором или иными, столь же неизящными словосочетаниями, - это первая программа, с которой сталкивается пользователь любой POSIX-совместимой ОС. И с ним же последним он расстается, выходя из системы. А все его действия во время работы - суть прямые или опосредованные команды, выполняемые в среде шелла. И даже если основная часть работы пользователя проходит в графическом режиме, в окружении интегрированных сред или оконных менеджеров, - окно терминала с приглашением командной строки быстро станет неотъемлемым атрибутом любого десктопа. Ибо, как я пытался показать в главе 12 и ряде интермедий, именно команды оболочки - самый простой и эффективный путь к выполнению всех операций по управлению файлами, многих задач обработки текста, да и просто запуска любых программ, что в консоли, что - в графическом режиме.

Кроме того, всегда следует помнить, что вообще функционирование Unix-подобной системы в значительной мере происходит в шелл-среде. Ибо шелл-сценариями являются все скрипты инициализации системы, многие общесистемные и пользовательские конфигурационные файлы, такие системы управления пакетами, как порты FreeBSD и портежи Gentoo Linux. Ну и то, что любой пользователь свободных ОС рано или поздно начинает писать собственные сценарии оболочки - неизбежно, как распад мировой системы социализма (кто еще не начал - уж поверьте мне на слово, хотя скажи мне такое лет пять назад - ни в жисть бы и сам не поверил).

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

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

Имя исполняемого файла, запускающего login shell (вместе с полным путем к оному - например, /bin/sh) - атрибут учетной записи каждого реального пользователя системы. Теоретически в этом качестве могут выступать не только собственно шеллы (то есть командные оболочки), но и интерпретатор какого-либо языка программирования (например, Tcl), программа типа Midnight Commander или даже текстовый редактор. Однако эти случаи - специальные, и далее рассматриваться не будут.

Второй аспект использования шелла - неинтерактивный. Неинтерактивный шелл - это экземпляр командной оболочки, вызываемый при выполнении пользователем любой команды или любого сценария. Он может быть вызван неявным или явным образом. Первый случай имеет место быть при выполнении команды из строки оболочки - ведь в этом случае, как мы видели в главе 7, посредством системного вызова fork создается точная копия породившего процесса (то есть той же интерактивной оболочки), а уже она вызовом exec запускает на исполнение введенную пользователем команду. Явный же вызов шелла происходит при выполнении сценариев оболочки - любой из них запускает собственный экземпляр командного интерпретатора.

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

#!/bin/bash

То есть после символов решетки (#) и восклицания (! - видимо, для пущей экспрессии) следует указывать полный абсолютный путь к исполняемому файлу, оболочку запускающему. Делается это, в том числе, и во избежание недоразумений - так, просто единичный символ решетки в первой строке может быть интерпретирован не как комментарий, а как указание на запуск командной оболочки csh. И если сценарий был написан не для нее (а, например, для того же /bin/sh) - он, в силу различия синтаксиса, просто не будет выполнен.

Подчеркнем еще раз: хотя команда, запускающая интерактивный или неинтерактивный шелл, может носить то же имя, что и команда на запуск login shell (а в Linux, скажем, обычно так и есть), это - разные экземпляры программы, которые в общем случае могут быть настроены независимо. А значит - и вести себя разным образом. И потому не следует удивляться, когда bash в эмуляторе терминала не реагирует на управляющие клавиши, привычные для того же bash в виртуальной консоли. А Midnight Commander отказывается в своей командной строке опознавать пути к исполняемым файлам.

Очевидно, что претензии пользователя к интерактивному (особенно к пользовательскому login shell) и неинтерактивному шеллам могут быть разными. В первом случае, как явствует из названия, важнее всего удобство интерактивной работы - развитые средства автодополнения, работы с историей команд, возможности гибкой и информативной настройки приглашения командной строки. Для неинтерактивного же шелла на первый план выходят быстродействие и совместимость.

С быстродействием все понятно - когда единственной задачей командной оболочки является вызов на исполнение другой команды (или, в случае скрипта, серии связанных команд) - тратить ресурсы на обеспечение дополнительных возможностей было бы излишеством. А вот о совместимости следует сказать особо. Но сначала - несколько слов о том,

Какие бывают шеллы

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

Оболочки, относимые к sh-совместимым, происходят от первой командной оболочки первых Unix-систем, которую так и называют - shell или Bourne Shell (то есть шелл Борна). В ней были заложены многие возможности для интерпретации команд и их конструкций, то есть составления системных и пользовательских сценариев. Однако по своим интерактивным возможностям она оставляла желать лучшего, и потому на базе ее была создана оболочка Корна (Korne Shell).

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

Следует заметить, что соответствие этому стандарту - один из критериев отнесения некоей ОС к семейству Unix или Unix-подобных. В частности, именно такой стандартизированный шелл должен вызываться при исполнении общесистемных сценариев инициализации любой POSIX-системы. Сам же по себе POSIX shell - некая мифическая абстракция, ближе к которой подходят /bin/sh - умолчальная пользовательская оболочка из FreeBSD, и ash, принятая в качестве стандартной в NetBSD (а также широко используемая во всяких мини-дистрибутивах Linux).

Шеллы и Борна, и Корна не были свободно распространяемыми программами в терминах GPL-совместимых лицензий. Поэтому ни тот, ни другой не могли использоваться в таких ОС, как *BSD или Linux, хотя свободная реализация оболочки Корна (pdksh) и была создана. Однако, как и ее прототип, шелл Корна, она, несколько развившись относительно первозданного Bourne shell, обладала интерактивными достижениями, уже далекими далекими от идеала. Столь же слабы они были и в ash. И потому наиболее широкое распространение из всего sh-совместимого семейства получила оболочка bash (что расшифровывается как "еще одна оболочка Борна", "заново рожденный шелл" и тому подобным образом), разработанная в рамках проекта GNU.

Популярность bash в немалой степени была обусловлена его интерактивными возможностями - он аккумулировал все достижения интерактивной мысли sh- и csh-совместимых оболочек, прибавив к ним немало собственных. И умудрившись при этом сохранить базовую совместимость с POSIX shell. Конечно, многие его собственные особенности (так называемые "bash'измы") выходили за рамки этого стандарта. Однако для соответствия оному был предусмотрен режим совместимости - то есть bash был способен эмулировать стандартный POSIX shell.

Однако главным для популярности bash было то, что эта оболочка оказалась тесно интегрирована с операционной системой Linux: именно bash волею судеб стал одной из первых программ, которые Линус запустил поверх своего новосозданного ядра. И потому идеи bash-скриптинга пронизали Linux до самых его оснований. Ну а для совместимости использовался тот самый режим эмуляции: в Linux файл, запускающий POSIX shell (по стандарту он должен именоваться /bin/sh), являет собой жесткую или символическую ссылку на реальный /bin/bash. Последний же, будучи вызванным таким образом, полностью воспроизводит функционально стандартный POSIX shell (разумеется, путем утраты своих продвинутых функций).

Клан csh-совместимых оболочек развивался параллельно сынам и пасынкам Борна. Собственно оболочка csh (или C-shell) была создана в Университете Беркли на начальных этапах реализации проекта BSD Unix. Первым ее разработчиком был Билл Джой - автор также и культового текстового редактора юниксоидов, vi, а в последующем один из основателей фирмы Sun.

Оболочка C-shell получила дополнительные интерактивные возможности, во многом превосходящие таковые не только у современного ей шелла Борна, но и появившегося позднее шелла Корна. Главное же - языку, ею интерпретируемому, были приданы черты синтаксического сходства с языком Си (откуда, собственно, и название - C-Shell, хотя не следует думать, что на всамделишний Си ее интерпретируемый язык похож). В результате оболочка csh оказалась весьма эффективной как для интерактивной работы, так и при создании сценариев. Только вот сценарии эти не были совместимы со скриптами POSIX shell, обретшего уже силу стандарта. То есть, при всей эффективности пользовательского шелл-программирования, для создания общесистемных сценариев она оказалась практически непригодной.

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

В частности, оболочка tcsh принята в качестве login shell для суперпользователя во FreeBSD. Правда, вызывается она в режиме совместимости с csh, однако /bin/csh - не более чем жесткая ссылка на /bin/tcsh.

Оболочка tcsh используется в качестве универсального "умолчального" пользовательского шелла также в OpenBSD и DragonFlyBSD. Однако характерно, что все общесистемные сценарии в обеих ОС написаны, тем не менее, в соответствие с требованиями POSIX Shell.

Принципы конфигурирования

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

Содержание профильного файла, как правило, - это переменные среды, которые должны наследоваться всеми процессами, как запущенными командами из строки пользовательского шелла, так и теми, что запускаются из пользовательских сценариев. В их числе такие, как тип терминала (переменная TERM), каталоги для поиска исполняемых файлов и man-страниц (переменные PATH и MANPATH, соответственно), имя редактора и pager'а по умолчанию (EDITOR, PAGER). В rc-файл резонно помещать переменные переменные оболочки и псевдонимы команд, имеющие смысл только для интерактивно запускаемых экземпляров шелла. Впрочем, это не обязательно - подчас профильный файл содержит единственную строку, предписывающую прочитать содержимое rc-файла для данного шелла (в котором и определяются все параметры пользовательского окружения).

Имена конфигурационных файлов различны в разных оболочках. В sh-совместимых оболочках конфиг для login shell обычно имеет в своем имени слово profile (откуда и пошло - профильный файл), имя интерактивного конфига образуется по модели shell_namerc. Место размещения общесистемных шелловских конфигов - обычно каталог /etc - эти файлы будут считываться в любом случае для login shell любого пользователя, и для любого экземпляра запущенного каждым пользователем интерактивного шелла. И их изменение - компетенция исключительно администратора системы.

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

А относительный порядок считывания профильного и rc-файла также различен в разных оболочках, и сложился он исторически. Первый шелл Борна имел один-единственный набор конфигов - общесистемный /etc/profile и пользовательские ~/.profile). И когда в его клонах появились отдельные конфиги для интерактивных шеллов - они считывались после профильного в таком порядке:

/etc/profile -> /etc/shrc -> ~/.profile -> ~/.shrc

В C-shell изначально имелось два конфига - общий cshrc и login - конфиг для пользовательского шелла. Причем первый считывался при старте любого экземпляра шелла, в том числе и запускаемого при авторизации. Лишь после этого определялось, является ли данный экземпляр шелла пользовательским, и если да - происходило считывание файла login:

/etc/csh.cshrc -> /etc/csh.login -> ~/.cshrc -> ~/.login

Имена C-конфигов могут меняться в разных ОС и дистрибутивах (приведенный пример относится к FreeBSD и DragonFlyBSD). Однако порядок обращения к ним унаследован современным свободным клоном C-shell - tcsh (именно он под именем /bin/csh фигурирует на самом деле во всех BSD-системах).

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

Да, чуть не забыл сказать: в приведенных примерах молчаливо предполагалось, что исполняемый шелл и его общесистемные конфиги находятся непосредственно в подкаталогах корня файловой системы (/bin и /etc, соответственно). Это отнюдь не обязательно: например, файлы bash bkb zsh, установленных из портов FreeBSD, будут иметь своим местопребыванием по умолчанию подкаталоги в /usr/local, в дистрибутивах Linux все оболочки, кроме общесистемной bash, окажутся, скорее всего, в подкаталогах /usr, и так далее. Однако очень важно, чтобы login shell пользователя root был собран (с помощью соответствующих опций, о чем говорилось в главе 14) так, чтобы его исполняемый файл и конфиг инсталлировались бы именно в /bin и /etc: иначе они окажутся недоступными в однопользовательском режиме, когда такие ветви файловой системы, как /usr и /usr/local, могут быть просто не смонтированы.

Проблема выбора

Из приведенного краткого обзора можно видеть, что в плане шеллов выбор пользователя достаточно обширен. А ведь я остановился только на самых распространенных. Однако рискну предположить, что большинство начинающих пользователей Linux'а об этом не особо задумываются. Ведь во всех его дистрибутивах в качестве общесистемного шелла и пользовательского шелла по умолчанию принят bash, обладающий как развитыми средствами интерпретации, так и продвинутыми интерактивными возможностями, да еще при сохранении совместимости со стандартом. Так зачем, казалось бы, искать добра от добра?

Первый вариант ответа очевиден - добро это дополнительное ищется в тех случаях, когда необходима минимизация ресурсов. Когда bash, занимающий более полумегабайта на диске (и около полутора - в памяти) оказывается излишне громоздким и медленным. Впрочем, первое играет роль только для всяких rescue-систем на дискетах (и прочих "мелких" носителях), а второе на современных машинах нечувствительно. Тем не менее, маленький и быстрый шелл Альмкивста (ash) может оказаться подходящим не только в спасательных целях, но и для всякого рода скриптинга. Хотя работать в строке ash регулярно мне бы не хотелось...

Вторая причина поиска нового шелла - неудовлетворенность возможностями имеющегося. Эта проблема остро встает перед пользователями FreeBSD - уж очень убог его умолчальный login shell для обычного пользователя (/bin/sh) в плане интерактивной работы. Что особенно наглядно проступает в сравнении с могучим tcsh, каковой по определению получает в свое распоряжение root-оператор. А потому и простой юзер может поддаться искушению и выбрать себе тот же tcsh - хотя бы ради единства стиля работы (ведь на настольной машине тот же юзер, как правило, сам себе root).

Должен заметить, что именно при первом приобщении к FreeBSD я и перепробовал целый ряд доступных в ней шеллов. Благо через систему портов или коллекцию пакетов они столь же легко удалялись, как и устанавливались. Не обошел я своим вниманием и tcsh - и в целом остался им доволен. Как интерактивная оболочка tcsh, на мой взгляд, существенно превосходит bash. А простой, логичный и лаконичный синтаксис его языка немало способствует в деле шелл-скриптинга. Правда, в этом и кроется, пожалуй, единственный недостаток tcsh: даже виртуозное им владение не освобождает от необходимости хоть как-то изучать какой-либо POSIX-совместимый шелл - ведь общесистемные сценарии все равно пишутся на нем...

И, наконец, третья причина для изысканий - поиски идеала. А не они ли движут, осознанно или нет, изрядной долей пользователей свободных POSIX-систем? Спору нет, bash - оболочка хорошая, но до такого идеала явно не дотягивающая, слишком много в нем направлено на достижения баланса компактности и функциональности. И тут стоит присмотреться к Z-Shell, или просто zsh - оболочке с лучшими, пожалуй, интерактивными возможностями.

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

Sh-совместимые оболочки

Оболочку ash (и практически идентичный ей /bin/sh из FreeBSD) можно рассматривать в качестве POSIX-шелла par excellence. Интерактивные ее возможности проще всего охарактеризовать в сранении с более "продвинутыми" шеллами - и исключительно от противного. А именно: она не поддерживает автодополнения, не имеет удобных средств доступа к истории команд, и даже средства навигации по командной строке и редактирования оной сводятся к клавише Backspace и ее эквиваленту - Control+H. Встроенных команд также немного (около 20 десятков).

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

#!/bin/sh

будут исполняться в любой POSIX-совместимой системе, так как каждая из них содержит исполняемый файл sh - и именно в каталоге /bin.

Средства настройки /bin/sh также не блещут разноообразием. Штатно для этой оболочки предусмотрен единственный файл - /etc/profile (и парный ему пользовательский профильный файл - ~/.profile), считываемый при авторизации. Однако, как мы только что выяснили, применять /bin/sh в качестве login shell не очень удобно, а все прочие его экземпляры таким образом оказываются без всяких настроек окружения вообще - что тоже не есть хорошо. И потому для /bin/sh можно установить и второй конфиг, однако этот факт, как и имя такого файла, необходимо определить явным образом в /etc/profile (или в ~/.profile), например, таким образом:

ENV=etc/shrc; export ENV

или, соответственно, так:

ENV=$HOME/.shrc; export ENV

Это увеличивает гибкость настроек /bin/sh, приближая его к более развитым аналогам.

Следующей sh-совместимой оболочкой является bash. Ей посвящено немерянное число материалов, к которым я, не являясь ни ее любителем, ни, тем более, знатоком, добавить ничего не могу. Однако bash - наиболее распространенная среди пользователей Linux командная оболочка, выступающая в этой ОС к тому же общесистемной и умолчальной. Популярна она, насколько мне известно, и среди пользователей иных POSIX-систем, по крайней мере свободных. И потому не сказать о ней хоть пару слов здесь - нельзя.

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

Схема инициации bash предусматривает наличие пары файлов /etc/profile и /etc/bashrc (для пользовательского шелла и просто интерактивного его экземпляра, а также соответствующих им пользовательских конфигов - ~/.bash_profile и ~/.bashrc. Однако порядок их считывания имеет некоторую спцифику. При авторизации первым в любом случае считывается общесистемный профильный файл /etc/profile, вслед за ним - пользовательский профильный файл ~/.bash_profile, после чего происходит обращение к ~/.bashrc. Однако порядок обращения к конфигам может быть изменен при сборке пакета, и майнтайнеры дистрибутивов Linux широко пользуются этой его особенностью. А также особым положением файла /etc/profile - в него часто помещают переменные окружения (например, локально-зависимые), которые должны быть общими для всех пользователей данной системы.

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

  • BASH конспект, где кратко просуммированы все важные для пользователя данные по этой оболочке (копия);
  • Особенности работы оболочки bash, содержащей массу сведений по использованию ее в интерактивном режиме, настройке и т.д. (копия);
  • Advanced Bash-Scripting Guide - практически исчерпывающее руководство по программированию bash-скриптов, которое будет полезно при изучении любых Shell-совместимых оболочек.

А из "бумажных" изданий нельзя забывать о такой книге: Д. Тейнсли. Linux и Unix: программирование в shell. К.: Издательская группа BHV, 2001. В принципе она посвящена астрактному шеллу, но в ней оговорены все случаи, относимые именно к bash.

И, наконец, Z-Shell или, сокращенно, zsh. Эта оболочка также принадлежит к клану sh-совместимых. Причем существует мнение (и не только мое), что в ней нашли свое воплощение все прогрессивные тенденции таких развитых оболочек, как bash и tcsh. И, ознакомившись с его возможностями, с этим трудно не согласиться - в zsh есть все, что было хорошего в тех обеих оболочках, но, если так можно выразиться, в превосходной степени. А ознакомиться с ней можно в специальной статье.

Кое что о csh и tcsh

Оболочки семейства C-Shell не избалованы вниманием русскоязычных авторов, почему я и решил удеить им особое внимание. Тем более, что tcsh объединяет преимущества синтаксиса csh и удобные средства настройки и интерактивной работы bash: многие из них были ассимилированы в zsh.

Командная оболочка csh пришла к нам из BSD-мира и традиционно пользуется популярностью среди пользователей этих систем. Правда, изначальный ее вариант (собственно csh) не принадлежит к числу свободно распространяемых программ. И потому в открытых BSD-клонах используется ее разновидность от Open Sources- оболочка tcsh. Которую, впрочем, никто не запрещает применять и в Linux'е.

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

Си-подобный синтаксис встроенного языка cshtcsh) обеспечивает существенно больший лаконизм сценариев, чем в скриптах shell-совместимых интерпретаторов. Правда, именно при создании сценариев использование оболочки csh может быть ограничено ее несовместимостью со стандартом POSIX.

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

Далее, важное с точки зрения пользователя различие - обращение с путями к исполняемым файлам. Клоны шелла Борна при вводе команды перечитывают состав каталогов, включенных в качестве значений переменной PATH. В клонах же csh эти значения, считываясь один раз при старте, далее хранятся в чем-то типа собственного буфера, именуемого хэш-таблицей. В результате чего достигается выигрыш в быстродействии исполнения внешних команд. Оборотная сторона - при добавлении к одному из каталогов переменной PATH нового файла (типичный случай - при установке новой программы) оболочка csh его просто не увидит; то есть для вызова такой новой программы в текущем сеансе придется указывать полный путь к ее исполнимому файлу. Или - перестроить хэш-таблицу, для чего предназначена специальная встроенная команда rehash.

Наконец, в csh по иному определяются переменные. Если во всех POSIX-шеллах для этого достаточно задать имя и значение, то здесь этой цели служит специальная встроенная команда set, например:

set EDITOR joe

определит редактор по умолчанию. Впрочем, таким образом будет задана только переменная оболочки - средств экспорта их в среду в csh не имеется. Для задания переменных среды существует отдельная встроенная команда setenv:

setenv EDITOR joe

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

Командная оболочка tcsh - это вариант C-Shell с мощными возможностями дополнения имен файлов и редактирования командной строки; нельзя не отметить, что в оригинальной csh они развиты существенно слабее, чем, скажем, в bash. Тем не менее, tcsh полностью совместима со своим прототипом с точки зрения синтаксиса.

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

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

Среда tcsh содержит достаточно большое (говорят, больше 50, я считать поленился) количество встроенных команд. Полный их список можно получить с помощью команды builtins (к слову сказать, также встроенной), ответом на которую будет список вроде этого:

:
@          alias      alloc      bg         bindkey    break
breaksw    builtins   case       cd         chdir      complete   continue
default    dirs       echo       echotc     else       end        endif
endsw      eval       exec       exit       fg         filetest   foreach
glob       goto       hashstat   history    hup        if         jobs
kill       limit      log        login      logout     ls-F       nice
nohup      notify     onintr     popd       printenv   pushd      rehash
repeat     sched      set        setenv     secodec      secodey      shift
source     stop       suspend    switch     telltc     time       umask
unalias    uncomplete unhash     unlimit    unset      unsetenv   wait
where      which      while

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

Основные возможности, предоставляемые tcsh в интерактивном режиме, помимо собственно исполнения команд, включают:

  • редактирование командной строки;
  • дополнение слов (word completion) - как для путей, так и для команд;
  • хранение и воспроизведение истории команд;
  • управление текущими задачами (job control).

Редактор командной строки предоставляет средства навигации внутри нее, с возможностью изменения отдельных знаков и компонентов команд, их опций и аргументов.

Навигация по командной строке и ее редактирование осуществляется двумя различными способами. Первый - использование стандартных клавиш управления курсором, таких, как Left и Right, Home и End, для навигации, и клавиш Delete и Backspase - для редактирования. Достоинство его - в простоте, вернее, в привычности: в ряде случаев эти клавиши ведут себя так же, как и в программах для DOS/Windows. Однако - далеко не всегда: на многих типах терминалов хоть какая-то из этих клавиш (а то и все сразу) обнаруживают аномальные особенности поведения.

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

Управляющие комбинации (bindkeys) в большинстве случаев имеют вид Control+литера (то есть литерная клавиша нажимается при нажатой клавише Control) или Escape-литера (когда литерная клавиша нажимается непосредственно сразу клавиши Escape). Все они не чувствительны к регистру и, насколько мне удалось выяснить, также и к раскладке клавиатуры (то есть работают, вне зависимости от переключения, например, с латиницы на кириллицу и обратно).

Полный список управляющих комбинаций для tcsh может быть получен командой

$ binkdkey

Одни из них дублируют стандартные клавиши перемещения курсора, такие, как:

  • Control+A - перемещение курсора в начало строки;
  • Control+E - перемещение курсора в конец строки;
  • Control+F - перемещение курсора на один знак вперед;
  • Control+B - перемещение курсора на один знак назад;

Другие же управляющие комбинации дают возможность перемещаться на одно слово вперед или назад (Escape-F и Escape-B, соответственно), в предыдущую позицию курсора (Control+X-X), удалять целиком слово (Escape-D) или часть строки после курсора, перемещать знаки (transpose-chars, Control+T), изменять регистр знаков и многое другое. А поскольку под все эти операции задействованы только клавиши основой части клавиатуры, скорость их выполнения - непревзойденная (при наличии некоторого навыка, доведенного, желательно, до рефлекторного уровня).

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

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

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

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

Для этого можно использовать клавиши управления курсором - Up (назад) и Down (вперед), с помощью которых как бы "пролистываются" по одной все ранее введенные команды. Аналогичного результата можно добиться и управляющими комбинациями - Control+P и Control+N или Escape+P и Escape+N, каждая пара из которых является аналогом пары Up и Down, соответственно.

Кроме этого, историю эту можно просмотреть с помощью встроенной команды history, которая выдаст нумерованный список всех выводившихся ранее (в количестве, определенном в файле конфигурации среды) команд, например:

$ history
1  17:19   logout
2  17:57   history
3  17:57   pwd
4  17:57   ls
5  17:57   ls -laFG
6  17:57   history

Любая из них вызывается в командную строку с помощью конструкции

!#

где # - порядковый номер команды в списке. Как и во всех прочих развитых оболочках, команду из истории можно отредактировать и (или) запустить на исполнение.

Общесистемные файлы конфигурации tcsh - файлы типа /etc/csh.cshrc и /etc/csh.login (точные имена в разных системах BSD-семейства, в базовый комплект которых входит эта оболочка, моут быть разными, пример приведен для DragonFlyBSD). При необходимости их аналоги, ~/.cshrc и ~/.login, создаются в домашнем каталоге пользователя. В отличие sh-совместимых оболочек, файлы csrc-группы считываются (сначала - общесистемный, затем - "домашний") при запуске любого экземпляра tcsh. Обращение же к файлу /etc/csh.login, а потом и к его "домашнему" аналогу - ~/.login, происходит только при запуске оболочки пользователя (login shell), хотя и после файлов cshrc-группы. Для csh порядок считывания dot-файлов определяется при компиляции и может быть изменен пересборкой оболочки.

Кроме того, в домашнем каталоге пользователя может обнаружиться еще два конфигурационных файла, считываемых последовательно после главных: истории команд ~/.history и ~/.cshdirs, в котором описываются стартовый каталог оболочки, если требуется сделать ее отличной от умолчального ~/ . При выходе из пользовательской оболочки выполняются действия, предписанные в файле /etc/csh.logout или ~/.logout.

Впрочем, в большинстве случаев пользователь вполне может обойтись единственным конфигом - ~/.cshrc (не считая ~/.history, который образуется и заполняется автоматически. Как пример, могу привести прокомментированное содержимое своего пользовательского dot-файла для tcsh.

# .cshrc - стартовый конфиг tcsh
# считывается при каждом запуске

# Псевдонимы для команд управления файлами

alias h		history 25
# Вывод последних 25 команд из файла истории

alias cp	cp -iR
# Рекурсивное копирование с запросом подтверждения перезаписи
alias cpf	cp -Rf
# Рекурсивное копирование с принудительной перезаписью

alias rm	rm -i
# Удаление файлов с запросом подтверждения

alias rmf	rm -Rf
# Принудительное рекурсивное удаление файлов

alias mv	mv -i
alias mvf	mv -f
# Перемещение/переименование файлов
# с запросом подтверждения и принудительно,
# соответственно

# Псевдонимы команды ls

alias ls	ls -FG
# Колоризованный вывод с типизацией файлов

alias la	ls -A
# Вывод всех файлов, за исключением . и ..

alias ll	ls -l
# Вывод списка файлов в "длинном" формате

alias li	ls -ial
# Вывод всех файлов в длинном формате с указанием идентификаторов

# Прочие псевдонимы
alias df	df -h
alias du	du -h
# Вывод с подбором единиц измерения

alias less	less -M
Вывод команды less в "more-подобном" виде

# Установка прав доступа для новообразованных файлов
umask 022

# Основные переменные оболочки и окружения

set path = (/usr/bin /usr/local/bin /usr/local/sbin /usr/X11R6/bin)
# Определение путей к исполняемым файлам

set autolist
# Вывод списка альтернатив для автодополнения
# по нажатию табулятора

set ignoreeof
# Запрет завершения сеанса по комбинации Control+D

set correct = cmd
# Автокоррекция команд

set histdup = erase
# Очистка файла истории команд от дубликатов

set prompt = '%~->'
# Установка вида приглашения

setenv	EDITOR	joe
setenv	PAGER	less
# Редактор и Pager по умолчанию

# Переменные для интерактивных экземпляров tcsh
if ($?prompt) then
	# Установить следующие переменные,
	# если определена переменная prompt
	set history = 1000
	set savehist = 1000
	# Установить число строк 
	# в истории команд текущего сеанса
	# и в файле истории, соответственно
	if ( $?tcsh ) then
		# Поведение клавиш (только для tcsh)
		bindkey "^W" backward-delete-word
		bindkey -k up history-search-backward
		bindkey -k down history-search-forward
	endif
endif

Приведенным примером возможности настройки tcsh отнюдь не исчерпываются - за подробностями можно обратиться к man tcsh.

[ опубликовано 23/09/2005 ]

Алексей Федорчук - Глава 15. Принципы сборки и установки пакетов   Версия для печати