Командная оболочка tcsh

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

Зачем нужен tcsh?

Для пользователя любого универсального дистрибутива Linux’а вопрос, вынесенный в заголовок, представляется более чем резонным. Ведь в его распоряжении по умолчанию имеется командная оболочка bash, причем, скорее всего уже настроенная «из коробки» — если и не идеальным для него образом, то вполне разумно и легко корректируемо. Если же и этих дополнительных возможностей bash окажется недостаточно — практически всегда можно установить zsh, функциональность которого при интерактивной работе вне конкуренции.

Иное дело во FreeBSD. Здесь в качестве командной оболочки для обычного пользователя (login shell) по умолчанию выступает так называемая /bin/sh — разновидность оболочки Альмквиста (ash), входящая в базовый комплект (base) FreeBSD Distributions и подлежащая установке при любом типе инсталляции этой ОС. Оболочка /bin/sh полностью соответствует стандарту POSIX для командных оболочек, описанному в соответствующем документе: Shell & Utilities. Это делает /bin/sh незаменимым инструментом для составления общесистемных и пользовательских скриптов, поскольку точное соответствие стандарту гарантирует их работоспособность в любой POSIX-совместимой операционке.

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

Конечно, и для пользователей FreeBSD дело обстоит не так печально, как кажется на первый взгляд: в этой системе в качестве портов и пакетов доступны практически все командные оболочки, созданные человечеством, в том числе, и bash вместе с bash-completion, и zsh. Однако их надо ещё тем или иным способом установить и, главное, настроить: без должным образом составленных пользовательских конфигов ни bash, ни, особенно, zsh не покажут своих интерактивных возможностей во всём блеске.

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

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

Что же до простоты настройки — тут уж tcsh оставляет далеко позади обе конкурирующие оболочки: для его конфигурирования требуется правка всего двух очень прозрачно устроенных конфигурационных файлов. Пользователь же bash должен всё время помнить о том, какие параметры обеспечиваются собственно профильными файлами этой оболочки (bash_profile и bashrc), а к каким он получает доступ благодаря библиотеке readline с её собственным конфигом (inputrc), какие функции доступны ему при базовой установке, а какие содержатся только в bash-completion. Что же касается zsh, то конфигурирование его для достижения полной функциональности вообще представляет собой очень не тривиальную задачу, требующую чтения многостраничной документации.

Правда, об одном коренном и неустранимом «недостатке» tcsh я должен предупредить сразу: даже виртуозное владение всем предоставляемым им функционалом не освобождает от необходимости хотя бы базовых представлений о синтаксисе POSIX Shell-совместимых интерпретаторов, к классу коих принадлежит поминаемый ранее /bin/sh: все общесистемные сценарии во FreeBSD написаны именно на нём, а язык интерпретатора tcsh с ними несовместим.

Впрочем, пользователи bash и zsh, относимых к классу sh-совместимых интерпретаторов, тоже должны помнить об отличиях языков сценариев для своих оболочек от чистого shell-скриптинга: не случайно в фундаментальной книге по программированию на Shell автор её, Дэвид Тейнсли, постоянно оговаривает все случаи использования «bash’измов».

Что же до языка C-Shell, используемого в интерпретаторе tcsh, то его несовместимость с чистым POSIX Shell компенсируется простотой и лаконичностью, что делает его более чем пригодным для сочинения пользовательских сценариев индивидуального применения.

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

C-shell и tcsh

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

# echo $SHELL

которая даст вывод

/bin/csh

В каталоге же /bin можно обнаружить два исполняемых файла:

% ls /bin/*csh                                                          11:22
/bin/csh*	/bin/tcsh*

Пояснение: в настоящем очерке, в соответствии с умолчаниями оболочек семейства C-shell, для обозначения приглашения командной строки оболочки суперпользователя используется символ #, обычного пользователя — символ %.

Означает ли наличие двух разноименных файлов в каталоге /bin, что csh и tcsh суть разные оболочки? Отнюдь: команда

# ls -li /bin/*csh
2610 -r-xr-xr-x  2 root  wheel  354616  7 сен 15:34 /bin/csh*
2610 -r-xr-xr-x  2 root  wheel  354616  7 сен 15:34 /bin/tcsh*

показывает нам, что они имеют не только одинаковый размер (346 Кбайт), но и совпадающие идентификаторы (2610). То есть оба имени, и csh, и tcsh — это не более чем жесткие ссылки (hardlinks) на один и тот же бинарник (в скобках замечу, что жесткие ссылки не надо путать ни с копией файла, ни с псевдонимом команды, ни с символической ссылкой: это просто две записи в каталоге, относящиеся к одному и тому же inode с его набором данных).

Почему так получилось? Чтобы ответить на этот вопрос, придётся обратиться к истории.

Как известно, первой командной оболочкой для первозданного UNIX’а была программа, именовавшаяся сначала просто shell, написанная в 1978 году Стефаном Борном, вследствие чего за ней позднее закрепилось имя «шелл Борна» (Bourne shell). Язык её интерпретатора был основан на Algol 68, что определило мощные по тем временам возможности составления сценариев: достаточно сказать, что многие команды, позднее вошедшие в золотой фонд классических Unix-утилит (породивших, в свою очередь, BSD- и GNU-утилиты), первоначально были реализованы именно как shell-скрипты (примеры чему можно найти в книге Рассела Сейджа Приемы профессиональной работы в UNIX, изданной более 20 лет назад, но не потерявшей своего методического значения и по сей день).

Однако, средства интерактивной работы в первозданном шелле Борна были, мягко говоря, не очень хорошо развиты: если обратиться к известной сравнительной таблице оболочек для Unix Брайана Блэкмора, то во всех её строках, имеющих какое-либо отношение к интерактивности, можно видеть жирное N. То есть в ней не было ничего из того, к чему мы привыкли с младых ногтей: ни автодополнения, ни истории команд, ни возможности редактирования командной строки, ни даже возможности изменить вид приглашения командной строки.

Да, мы знаем, что потом всё это постепенно и по очереди будет появляться — сначала в шелле Корна (ksh), и в шелле Альмквиста (ash), и в bash (возрождённом шелле Бурна), и, наконец, в zsh, ставящем на сегодняшний день последнюю точку в развитии командных оболочек. Но сейчас-то мы находимся в далёких 70-х годах прошлого века, когда UNIX только вышел из родительских пенат AT & T и отправился в (почти) свободное плавание по университетам Америки, Европы и сопредельных стран вроде Австралии. Пришвартовавшись, в частности, и в университете Беркли, штат Калифорния.

В Университете Беркли в это время вовсю разрабатывался собственный вариант UNIX, который позднее получит имя BSD4.4 и ляжет в основу FreeBSD ( а также всех остальных свободных операционок берклианского семейства). И один из перворазработчиков BSD, Билл Джой, которому мы обязаны также текстовым редактором vi, уже в 1979 году предложил свою командную оболочку, получившую имя C-shell (или просто csh).

Почему? Если Борн при создании shell’п опирался на язык Алгол, то Джой для языка своего шелла применил синтаксис, сходный с таковым языка Си, исконного для UNIX. Это сделало оболочки sh и csh несовместимыми на уровне сценариев. Но зато в csh было добавлено множество интерактивных возможностей — автодополнение, буфер истории, средства навигации внутри командной строки и её редактирования, настройка вида приглашения, различие схемы настройки интерактивного и неинтерактивного шелла … Короче, всё то, что потом в той или иной мере инкорпорировали shell-совместимые оболочки, включая bash и zsh. И что ныне кажется нам неотъемлемым атрибутом любого шелла — всё это в конечном итоге происходит из csh.

Так что C-shell очень быстро стал непременной принадлежностью разрабатываемой в Брекли BSD-системы — в отличие от коммерческих UNIX’ов, стандартные оболочки которых, вроде ksh, развивали традиции шелла Борна (хотя и, как только что говорилось, с опорой на достижения csh).

Впрочем, интерактивные возможности csh были далеки от идеала. Что особенно почувствовалось в начале 90-х годов, когда, с одной стороны, произошло освобождение BSD-систем в лице NetBSD и FreeBSD от тяжелого наследия проприетарного режима лицензирования. А с другой — началось победное шествие Linux’а с его стандартной оболочкой GNU bash, обходящей древний csh на несколько корпусов.

И тогда разработчики FreeBSD вспомнили об оболочке tcsh, которая, основываясь на синтаксисе C-shell, с давних времен разрабатывалась сначала Кэном Григом в университете Карнеги-Меллона, а затем Полом Плэйсвэем в университете Огайо. Чем она была примечательна?

Изначально tcsh создавалась по образу и подобию командного интерпретатора операционной системы TENEX — собственно, имя её и означает TENEX csh. А особенностью TENEX — древней, еще до-Unix’овой, операционки (из недр которой, кстати, происходит и знаменитая «собака» в адресах электронной почты) были чрезвычайно длинные команды, да ещё и с избыточными словами «для ясности». С такими командными директивами было бы трудно работать без развитых средств навигации и редактирования командной строки, каковые и стали отличительными особенностями TENEX C-shell.

Таким образом, tcsh утвердился в роли стандартной оболочки FreeBSD, а позднее OpenBSD, DragonFlyBSD и юзер-ориентированных потомков BSD-клана, таких как PC-BSD и DesktopBSD. Однако и имя csh было оставлено в файловой иерархии FreeBSD как реликт предшествующей эпохи. Однако теперь оно соответствовало не самостоятельной оболочке, а было, как уже говорилось, лишь жесткой ссылкой на тот же tcsh.

Вопреки сказанному в предыдущей моей заметке об оболочках семейства C-shell, поведение csh и tcsh при прочих равных условиях (то есть одних и тех же файлах конфигурации) абсолютно идентично: tcsh, запущенный под именем csh, не эмулирует изначальный C-shell (как это имеет место для bash и zsh, запускаемых в качестве /bin/sh). А кажущаяся бедность умолчального csh/tcsh в севежеустановленной FreeBSD обусловлена исключительно его настройками — точнее, почти полным отсутствием таковых, в чём легко убедиться, заглянув в конфигурационные файлы /etc/csh.cshrc, /etc/csh.login, /root/.cshrc и /root/.login.

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

TENEX C-shell: общий обзор

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

Как уже было сказано, tcsh входит в состав базового комплекта FreeBSD Distributions, который устанавливается при любом типе инсталляции этой системы. И также обязательно эта оболочка имеется в составе OpenBSD и DragonFlyBSD (вероятно, она есть и в базовом наборе NetBSD). Но и дистрибутивы Linux общего назначения ею не обделены: если её не найдется на установочных дисках, то почти наверняка прекомпилированный для данного дистрибутива пакет tcsh имеется в его официальном или пользовательском репозитории, откуда может быть установлен штатными средствами. Так что к скачиванию исходников и их сборке придётся прибегнуть лишь в особых случаях — в разделе о настройках я скажу, в каких именно.

Текущая версия tcsh на данный момент — 6.15, датированная мартом 2007 года. И из истории её обновлений можно видеть (например, здесь), что в последние годы программа обновлялась не очень активно. Это не значит, что проект tcsh замер: просто оболочка дошла в своём развитии до некоторой логической черты, после которой требует лишь косметических улучшений.

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

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

Как интерактивная среда, tcsh предоставляет в распоряжение пользователя следующие функции:

  • большое количество встроенных в оболочку команд, в том числе, команд для управления (определения и отмены) псевдонимами и переменными — как переменными оболочки, так и переменными среды, а также операторами;
  • средства навигации по командной строке и редактирования её компонентов с помощью как стандартных клавиш управления курсором, так и многочисленных встроенных управляющих последовательностей (keybindings);
  • возможность автодополнения не полностью введённых элементов командных конструкций; в отличие от изначального csh, автодополнение распространяется не только на пути к файлам в аргументах команд, но и на сами команды;
  • использование шаблонов в именах файлов, задаваемых в качестве аргументов команд;
  • просмотр буфера истории команд, поиск в нём и извлечение команд для повторного исполнения;
  • фоновое исполнение команд и средства управления запущенными заданиями;
  • средства тонкой настройки поведения оболочки в интерактивном режиме, в том числе, вида приглашения командной строки с целью придания ему наибольшей информативности и (или) компактности.

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

Наконец, целям csh-скриптинга служат операторы — условные, циклические и многовариантные.

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

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

Оборотная сторона выигрыша в скорости вызова внешних команд также налицо: при добавлении к одному из каталогов переменной PATH нового файла (типичный случай — при установке нового пакета) оболочка tcsh его просто не увидит. То есть для вызова такой новой программы пришлось бы либо выходить из данного сеанса и авторизоваться заново, либо, в текущем сеансе, — указывать полный путь к ее исполнимому файлу. Благо, есть иная возможность — перед запуском исполняемого файла вновь установленного пакета модифицировать хэш-таблицу, для чего предназначена специальная встроенная команда rehash.

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

% set nobeep

приведёт к отмене звукового сигнала, подача которого включена по умолчанию.

Переменные могут иметь некоторые предопределённые значения. В этом случае они присваиваются через знак равенства. Так, установка переменной

% set correct = cmd

включит коррекцию ошибок при наборе команд, а значение all распространит коррекцию и на пути в их аргументах.

Средств для экпорта переменных оболочки в среду tcsh не предусматривает. Вместо этого для задания переменных среды существует специальная встроенная команда setenv. Так, конструкция

% setenv PAGER less

установит в качестве «листателя страниц» (вызываемого, например, при обращении к man-документации) less (вместо умолчального more). Обратим внимание на различие синтаксиса команд set и setenv: во втором случае присвоение значения переменной знака равенства не требует.

В отличие от sh-совместимых оболочек, в tcsh имена в нижнем регистре имеют встроенные переменные оболочки, такие, как shell, user, history, а имена переменных, определяемых пользователем, подобно PAGER, EDITOR, BLOCKSIZE, принято задавать в регистре верхнем.

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

«Разопределение» переменных оболочки выполняется с помощью команды unset, переменных среды — unsetenv, обе из которых в качестве аргумента требуют указания имени отменяемой переменной. Вопреки ожиданиям, unset и unsetenv, заданные без аргументов, вызовут не отмену всех определённых с их помощью переменных, а сообщение об ошибке:

% unset
unset: Too few arguments.

Мелкие различия между семействами sh и csh существуют также в назначении псевдонимов. И там, и там для этого служит встроенная команда alias. Но если в первом случае она требует оператора присваивания и экранирования значения псевдонима строгими кавычками, то в tcsh достаточно такой формы:

% alias less less -M

Она придаст команде less так называемый «more-подобный» вид (с указанием в статусной области полного пути к просматриваемому файлу, диапазона выведенных на экран строк и общего количества строк в файле).

Впрочем, резонные люди всё равно и в tcsh рекомендуют экранировать значение псевдонима строгими кавычками.

Команда alias без указания аргументов выведет полный список задействованных псевдонимов. А их «развоплощение» осуществляется командой unalias с именем (но не значением) псевдонима в качестве аргумента. Как и в случае с unset и unsetenv, команда unalias без аргумента не даст никакого результата, кроме сообщения об ошибке.

Некоторая специфика tsch проявляется и в перенаправлении ввода-вывода. Так, в этой оболочке не предусмотрено обращение к стандартным дескрипторам (ввода, вывода и диагностических сообщений) по их традиционным номерам (0, 1, и 2 соответственно). И потому конструкция типа 2 > /dev/null, подавляющая вывод на экран нежелательных сообщений об ошибках (особенно часто это требуется при использовании утилит find и grep), оказывается невозможной. Зато конструкция >& отправит в небытие и стандартный вывод, и стандартную диагностику скопом.

Решение задачи подавления вывода нежелательных сообщений об ошибках нашлось благодаря Полячку на форуме POSIX.ru в виде такой конструкции:

% (command > out)>& err

где command — команда со всеми её опциями и аргументами, out — условное имя файла, в который перенаправляется «полезный» вывод команды, а & в данном контексте представляет весь остаток от оного, то есть сообщения об ошибках, которые помещаются в файл err. Имя последнего также условно, так что никто не запрещает подменить его сакраментальным /dev/null.

Конструкция далеко не столь проста и изящна, как в sh-совместимых оболочках типа bash и, тем более, zsh (где команде с операцией перенаправления можно вообще определить глобальный псевдоним). В частности, для просмотра «полезного» вывода она потребует ещё одной команды — вызова какого-либо пейджера вроде less:

% (command > out)>& err ; less out

Но эта конструкция имеет одно неоспоримое достоинство — она работает.

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

А теперь, установив в первом приближении специфику оболочки tcsh, рассмотрим некоторые её особенности более подробно.

Встроенные команды, псевдонимы и переменные

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

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

:          @          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     settc      setty      shift
source     stop       suspend    switch     telltc     termname   time
umask      unalias    uncomplete unhash     unlimit    unset      unsetenv
wait       where      which      while

Со списком встроенных команд можно ознакомиться также на странице

% man builtins

Причём из приводимой там таблицы легко определяется, какие встроенные команды tcsh имеют дублей в оболочке /bin/sh, а какие — и «однофамильцев» во внешнем мире.

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

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

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

Так, в предыдущем разделе говорилось о командах определения псевдонимов. Однако в tcsh существуют также встроенные (то есть зарезервированные) псевдонимы, перечисленные в следующем приложении.

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

  • user, значением которой является имя пользователя, зарегистрированного в данном сеансе;
  • shell, принимающей имя командной оболочки, запускаемой при регистрации пользователя (так называемый login shell);
  • term, определяющей тип используемого им терминала;
  • tty, указывающей имя собственное конкретного терминала в данном сеансе.

Значения этих (и любых других установленных) переменных можно получить с помощью встроенной команды echo. Например, последовательность команд

echo $user ; echo $shell ; echo $term ; echo $tty

выведет информацию о сеансе пользователя в следующем виде:

alv
/bin/tcsh
xterm
ttyp2

Если переменная не определена, вывод команды echo любезно проинформирует нас об этом:

echo $ignoreoff
ignoreoff: Undefined variable.

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

Навигация и редактирование командной строки

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

Навигация по командной строке и ее редактирование могут осуществляться двумя различными методами. Первый — использование стандартных клавиш управления курсором, таких, как Left и Right, Home и End для навигации, и клавиш Delete и Backspase — для редактирования.

Достоинство «стандартного» способа — в его не столько даже простоте, сколько в привычности для многих пользователей: в большинстве случаев стандартные клавиши управления курсором с клавиатуры ведут себя так же, как и в программах для DOS/Windows. Однако — отнюдь не всегда: на некоторых типах терминалов хотя бы какая-то из этих клавиш (а то и все сразу) обнаруживают аномальные особенности поведения. Да и возможности их ограничены функциями наличествующих на клавиатуре клавиш.

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

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

Управляющие комбинации клавиш (bindkeys) в большинстве случаев имеют вид Control+литера или Meta+литера.

С первым случаем всё ясно: литерная (точнее, алфавитно-цифровая, в общем случае — символьная) клавиша нажимается при нажатой управляющей клавише Control.

А вот клавиши Meta мы на клавиатуре PC не найдём: её роль исполняет либо нажатие клавиши Alt (и, для приведения в действие управляющей последовательности, одновременное нажатие символьной клавиши), либо нажатие и отпускание клавиши Escape, после чего сразу нажимается символьная клавиша.

Все управляющие Control-последовательности в tcsh не чувствительны к регистру и, насколько мне известно, также и к раскладке клавиатуры. То есть они работают (и работают одинаково) вне зависимости от переключения, например, с латиницы на кириллицу и обратно. Не влияет на них и тип терминала: действие управляющих последовательностей абсолютно идентично в системной консоли FreeBSD и DragonFlyBSD, в wscons из Net- и OpenBSD, в Linux-консоли и во всех Иксовых программах-эмуляторах терминалов, которые я видел.

С Meta-последовательностями несколько сложнее. Во-первых, во всех интегрированных десктопах алфавитные комбинации с клавишей Alt задействованы под внутренние нужды среды (за KDE и Xfce уверен, думаю, что и GNOME не прошли мимо неё); как помнится, в некоторых оконных менеджерах Alt тоже используется для собственных целей. То есть в Иксовых эмуляторах терминалов, вне зависимости от их собственных свойств, выступать как Meta-клавиша она не может: в этой роли безальтернативно выступает только клавиша Escape.

Во-вторых, в средах, основанных на библиотеках Gtk, клавиатурные комбинации категорически отказываются работать при переключении на русскую раскладку клавиатуры. Это не какая-то особая нелюбовь именно к управляющим Meta-последовательностям tcsh, не функционируют при этом обычно и стандартные для Иксовых приложений комбинации типа Control+C и Control+V. Почему чаша сия миновала Control-последовательности tcsh — остаётся только гадать.

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

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

$ binkdkey

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

  • Control+A — перемещение курсора в начало строки, аналогично клавише Home;
  • Control+E — перемещение курсора в конец строки, аналогично клавише End;
  • Control+F — перемещение курсора на один знак вперед (аналог клавиши Right);
  • Control+B — перемещение курсора на один знак назад (аналог клавиши Left).

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

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

А поскольку под все эти операции задействованы только клавиши основой части клавиатуры, скорость их выполнения — непревзойденная (при наличии некоторого навыка, доведенного, желательно, до рефлекторного уровня).

Автодополнение

Следующая неоценимая возможность tcsh — автоматическое дополнение слов, не полностью введённых в командной строке. Как мы помним из исторического обзора, эта функция впервые появилась в предшественнике tcsh — чистом C-shell, но там она действовала только по отношению к именам файлов и путям к ним в аргументах команд, но не самим командам. И осуществлялось она не клавишей табуляции, как позднее в bash и zsh (да и в tcsh тоже, о чём скоро будет сказано), а встроенными управляющими последовательностями — Control+I для дополнения в случае безальтернативности и Control+D — для вывода возможных вариантов продолжения набора.

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

В tcsh автодополнение работает как для команд, так и для имен файлов и путей к ним, хотя по умолчанию и несколько иначе, чем в bash и zsh. Так, при наборе первых символов команды или имени файла (пути к нему) в её аргументе автоматическое дополнение осуществляется (при его однозначности) как клавишей табуляции, так и унаследованной от csh управляющей последовательностью Control+I.

В случае наличия вариантов продолжения команды или имени ни нажатие клавиши табуляции, ни последовательность Control+I не дадут никакого результата (кроме, может быть, писка динамика, если включён звуковой сигнал — о чем будет говориться позднее). Однако с помощью управляющей последовательности Control+D можно вызвать список возможных вариантов продолжения набора.

Отступление: внимательный читатель обратил внимание, что это уже второй вариант использования последовательности Control+D. Так оно и есть: действие этой комбинации клавиш зависит от позиции курсора в момент её введения. В редакторе командной строки, при нахождении курсора в середине последней, она удаляет следующий за курсором символ.

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

Наконец, последовательность Control+D, введённая в пустой командной строке, оказывает уж совсем неожиданное (или, напротив, вполне предвидимое) действие: вместо того чтобы по аналогии с клавишей табуляции в bash’е вывести список всех доступных (то есть прописанных в переменной path) команд, она интерпретируется как символ окончания файла, в данном случае — файла устройства стандартного ввода. Результатом чего будет… правильно, выход из командной оболочки, аналогично действию по команде exit. Правда, можно принять меры к предотвращению такого, как правило, нежелательного исхода, о чем будет сказано в разделе о настройке tcsh.

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

% set autolist

Если есть желание увековечить такое поведение — то это определение нужно занести в профильный файл, о чём также будет сказано позднее.

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

История команд

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

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

% history1	9:46	echo $tty
	2	9:47	man builtins
	3	10:47	echo $term
	4	10:54	echo $term
	5	10:55	echo $user ; echo $shell ; echo $term ; echo $tty
	6	10:59	echo $ignoreoff
	7	15:34	ls -a
	8	15:34	less .history
	9	15:42	history

Количество команд в выводе можно ограничить указанием их числа в качестве аргумента; так, при задании команды в форме

% history 5

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

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

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

% history | less

а некую конкретную команду — отыскать с помощью утилиты grep:

% history | grep set

Содержимое файла ~/.history можно просмотреть и непосредственно — это обычный текстовый файл, доступный для обработки стандартными утилитами типа less, grep и тому подобными. В принципе, ничто не препятствует его обработке с помощью неинтерактивных утилит вроде ed или sed, или даже текстового редактора.

Главное назначение буфера истории команд и команды его просмотра — предоставить возможность извлечения ранее исполнявшейся команды из истории и ее повторного исполнения.

Так вот, любая из команд буфера вызывается в командную строку с помощью директивы

% !#

где # — порядковый номер команды в списке вывода history. После этого команду из истории можно запустить на исполнение или предварительно отредактировать её точно так же, как и команду, только что введённую с клавиатуры.

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

Интерактивный просмотр буфера истории в tcsh имеет очень полезную особенность: если в пустой командной строке набрать какой-либо символ и начать просматривать буфер с помощью клавиши Up или комбинации Control+P (Meta+P), то из буфера истории будут извлекаться только команды, имена которых начинаются с этого символа. Введение двух и более начальных символов ещё более сузит круг вывода. С помощью дополнительных настроек это можно реализовать и в bash, но в tcsh этот приём работает, что называется, «из коробки» (хотя здесь его, напротив, можно и запретить в профильных файлах).

Прочие возможности tcsh

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

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

  • символ * заменяет любую последовательность любых символов за исключением начальной точки в именах скрытых файлов: её надо указывать явным образом;
  • символ ? заменяет любую единичную литеру или цифру;
  • набор символов [?-?] определяет диапазон литер или цифр, подставляемых в имена файлов;
  • в набор символов {*,*,*} можно вставить целые слова, которые будут помещены в имена файлов.

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

Для фонового исполнения команда запускается с символом & в конце командной конструкции, после чего возвращается приглашение командной строки, и становится возможным ввод следующей команды, которая также может определяться как фоновая. Команда jobs выводит список всех запущенных команд (и фоновых, и активных) с указанием их номеров. Для перевода фоновой команды в активный режим служит команда fg с указанием номера задания; команда bg, напротив, переводит активную задачу в режим фонового исполнения.

Наконец, последнее, о чём надо сказать пару слов — это об операторах, которые упоминались в разделе о встроенных командах как одна из их разновидностей.

В tcsh поддерживаются условные операторы и операторы цикла. Условный оператор if, как явствует из его названия, определяет некоторое условие, при соответствии которому выполняется указанное действие, а при несоответствии — не происходит ничего или выполняется другое действие, что в общем виде выглядит так:

if (условие) thenла
	command1
else
	command2
endif

С примером условного оператора мы столкнёмся в следующем разделе при рассмотрении прототипа конфигурационного файла ~/.cshrc:

if ($?prompt) then
        set filec
        ...
endif

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

Оператором цикла while определяется некое условие, при истинности которого происходит непрерывное выполнение указанных за условием команд.

Оператор цикла foreach позволяет организовать цикл по элементам массива слов:

foreach name (wordlist)
...
end

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

И, наконец, многовариантный условный оператор switch позволяет передавать управление в зависимости от того, удовлетворяет ли строка string какому-либо шаблону из набора pattern1, pattern2, …( в этом случае управление передается в блок, ограниченный case … breaksw) или нет (в этом случае управление передается на ветвь default:… endsw):

switch (string)
case pattern1 :  ...  breaksw  case {it pattern2} :
...
breaksw
...
default:
...
endsw

Вообще, операторы — это совершенно отдельная тема, относящаяся уже не к пользованию как таковому, а к csh-скриптингу. Так что пока более насущным мне представляется

Конфигурирование tcsh

При установке оболочки tcsh (во FreeBSD это происходит вместе с системой) устанавливается три общесистемных конфигурационных её файла: /etc/csh.cshrc, /etc/csh.login, /etc/csh.logout, которые и определяют поведение оболочки. Первые два файла считываются при старте оболочки: /etc/csh.cshrc — при запуске каждого экземпляра tcsh в интерактивном режиме, /etc/csh.login — только в том случае, когда данный экземпляр tcsh является регистрационной оболочкой пользователя (login shell).

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

Обращение к файлу /etc/csh.logout происходит при завершении сеанса пользователя, для которого tcsh является регистрационной оболочкой.

Порядок обращения к конфигурационным файлам в tcsh по умолчанию отличается от такового в bash. При запуске каждого интерактивного экземпляра этой оболочки сначала происходит обращение к /etc/csh.cshrc. После этого осуществляется проверка того, является ли данный экземпляр tcsh регистрационной оболочкой пользователя. Если нет — процесс считывания заканчивается. Если же экземпляр tcsh представляет собой login shell, то происходит обращение к файлу /etc/csh.login.

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

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

Отступление: Кстати, а откуда берутся прототипы конфигурационных файлов при создании нового аккаунта? Ответ прост: они копируются из каталога /usr/share/skel/. И это касается не только dot-файлов для tcsh: если просмотреть этот каталог командой ls, то в нём можно увидеть заготовки конфигов и для /bin/sh, и для некоторых других программ:

% ls
dot.cshrc         dot.login_conf    dot.mailrc        dot.rhosts
dot.login         dot.mail_aliases  dot.profile       dot.shrc

Собственные же прототипы конфигов, если требуется распространить их среди всех новообразуемых пользователей, можно поместить в каталог /etc/skel. Впрочем, это совсем отдельная история.Кроме того, в домашнем каталоге пользователя может создаваться (непосредственно руками или с помощью скрипта конфигурирования) файл ~/.tcshrc: он является альтернативой для ~/.cshrc, и в случае его присутствия именно к нему происходит обращение при запуске интерактивного экземпляра оболочки; считывание ~/.cshrc осуществляется только в том случае, если ~/.tcshrc не будет найден в домашнем каталоге.

Далее, в домашнем каталоге пользователя могут присутствовать еще два dot-файла: ~/.history и ~/.cshdirs, а также файл ~/.logout. Первый файл обычно возникает и заполняется автоматически: в него записывается содержимое буфера истории команд каждого сеанса tcsh. Файл ~/.cshdirs при необходимости нужно создать собственноручно: как мы увидим ниже, в нём будет записываться стартовый каталог оболочки, если требуется сделать его отличным от принятого по умолчанию домашнего каталога пользователя. Файл ~/.logout по умолчанию отсутствует, и его также нужно создать руками.

Обращение к файлам ~/.history и ~/.cshdirs происходит только при запуске регистрационного экземпляра tcsh. Первый считывается непосредственно после ~/.tcshrc (или, при отсутствии последнего, после ~/.csh) и перед ~/.login. Файл ~/.cshdirs читается последним в ходе запуска регистрационного шелла.

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

etc/csh.cshrc -> /etc/csh.login -> ~/.tcshrc (~/.cshrc) -> ~/.history -> ~/.login -> ~/.cshdirs

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

При запуске просто интерактивного, не регистрационного экземпляра tcsh считываются только файлы etc/csh.cshrc и ~/.tcshrc (или ~/.cshrc, если последний отсутствует). По завершении его никаких действий не происходит.

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

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

Для начала обратимся к общесистемным конфигам /etc/csh.cshrc, /etc/csh.login, /etc/csh.logout — и с удивлением обнаружим, что они пусты. То есть в /etc/csh.cshrc и /etc/csh.logout нет вообще ничего, кроме стандартной шапки и сообщения, что это общесистемные файлы. А в /etc/csh.login можно видеть лишь три закомментированные строки, необходимость снятия комментариев с которых не очевидна. То есть по умолчанию поведение оболочки tcsh определяется исключительно её предопределёнными при сборке параметрами и настройками конфигов в пользовательском каталоге.

Так что, если умолчальное поведение tcsh нас хоть сколько-нибудь устраивает, но требует корректив, то оставляем в покое общесистемные конфиги и обращаемся к конфигам пользовательским. Исходя из их назначения и порядка считывания, резонно было бы предположить, что в файле ~/.cshrc или ~/.tcshrc надо устанавливать параметры, необходимые при интерактивной работе в оболочке всегда, вне зависимости от того, запущена ли она при регистрации в системе или нет — например, в терминальном окне системы X. В файле же ~/.login достаточно ограничиться только теми установками, которые должны быть общими для всего сеанса данного пользователя.

В сущности, как говаривал Аркадий Райкин, мы правы, но по существу — не то чтобы глубоко заблуждаемся, но должны принимать во внимание некоторые коррективы.

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

Далее, казалось бы, как общее свойство регистрационной оболочки логично было бы определить локально-зависимые переменные. Да, это возможно, но далеко не всегда оправданно. В современных дистрибутивах Linux системная локаль обычно определяется глобально, в общесистемных конфигурационных файлах (причём чуть не в каждом дистрибутиве — по своему). А во FreeBSD понятие системной локали, по существу, отсутствует: идеологически (да и практически) более правильно задавать локаль через класс пользователя.

При этом следует учитывать, что в текстовом режиме FreeBSD, вследствие восьмибитного внутреннего представления символов в её консольном драйвере (syscons), использование кодировки UTF-8, знаменующей собой светлое будущее всего человечества, невозможно. Поэтому юникодовскую локаль в этой системе приходится указывать в конфигах, определяющих условия запуска Иксов (типа ~/.xinitrc, ~/.xsessionrc или ~/.Xclients).

Получается, что в файле ~/.login определять собственно и нечего. Кроме, разве что, команд инициализации терминала и установок его опций, типа tset и stty — но многим ли они нужны в наше время на пользовательской машине? Кстати говоря, по умолчанию пользовательский ~/.login также фактически пуст — единственная строка в нём имеет отношение к запуску древней игры fortune и может быть спокойно ликвидирована, хотя жить она тоже не мешает.

Что же, конфиг из ~/ — юзеру легче. Значит, для редактирования у нас фактически остаются только два файла — ~/.cshrc и ~/.tcshrc, потому что ~/.history заполняется автоматически, с файлом ~/.cshdirs вообще особая история, а в ~/.logout требуется (если вообще требуется) внести одну-две строки.

На самом деле и двух файлов оказывается много: ~/.cshrc существует только для совместимости с иными платформами и ни во FreeBSD, ни в Linux’е не нужен — достаточен ~/.tcshrc. Почему его следует выбрать из двух, казалось бы, равноценных вариантов? Да потому, что в нём можно указывать параметры, не воспринимаемые чистым C-shell’ом.

Однако в нашем распоряжении после создания пользовательского аккаунта, использующего регистрационный шелл /bin/tcsh, и авторизации под новым именем имеется только файл ~/.cshrc с некоторыми минимальными, но вполне разумными настройками, который выглядит так:

alias h         history 25
alias j         jobs -l
alias la        ls -a
alias lf        ls -FA
alias ll        ls -lA# A righteous umask
umask 22

set path = (/sbin /bin /usr/sbin /usr/bin /usr/games /usr/local/sbin /usr/local/bin $HOME/bin)

setenv  EDITOR  vi
setenv  PAGER   more
setenv  BLOCKSIZE       K

if ($?prompt) then
        # An interactive shell — set some stuff up
        set filec
        set history = 100
        set savehist = 100
        set mail = (/var/mail/$USER)
        if ( $?tcsh ) then
                bindkey "^W" backward-delete-word
                bindkey -k up history-search-backward
                bindkey -k down history-search-forward
        endif
endif

Можно видеть, что он естественным образом распадается на ряд секций, хотя они и не выделены явным образом:

  • сначала идёт определение псевдонимов (alias) для наиболее употребимых команд;
  • затем устанавливаются права доступа по умолчанию для вновь образуемых файлов и каталогов;
  • далее определяются значения встроенной переменной path — в них включены все каталоги, в которых потенциально могут быть исполняемые файлы;
  • вслед за этим устанавливаются пользовательские переменные окружения — редактор и пейджер по умолчанию и единица измерения для блоков, в которых соответствующими утилитами выводится размер файлов, объем, занимаемый каталогами, объем занятого или свободного дискового пространства;
  • последняя секция — условный оператор, определяющий, по наличию переменной prompt, является ли данный экземпляр шелла интерактивным, и если да, устанавливающий ряд переменных, в том числе специфичных для tcsh.

Основываясь на «рыбе», доставшейся нам в комплекте, попробуем составить собственный файл ~/.tcshrc. Для начала озаглавим его:

# Мой пользовательский ~/.tcshrc
# Считывается при каждом запуске tcsh
# Работающий конфиг для FreeBSD 7.1

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

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

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

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-подобном" виде

alias wget	wget -c		# Скачивание по ftp
				# с продолжением

alias aspell aspell -c	        # Проверка орфографии

alias nano	nano -w		# Вызов nano без переноса слов

Теперь задаём атрибуты доступа для новообразованных файлов и каталогов:

umask 022

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

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

set path = (/bin /usr/bin /usr/local/bin)

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

Вслед за этим задаём значения пользовательских переменных окружения. Мне представляются удобными следующие:

setenv EDITOR	nano
setenv PAGER	less
setenv BLOCKSIZE K

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

set ignoreeof

игнорирующую символ окончания файла.

Заодно избавимся и от звуковых сигналов, действующих подчас раздражающе, в том числе и на близких:

set nobeep

Затем обеспечиваем вывод вариантов дополнения слов по нажатию клавиши табулятора:

set autolist

Автоматическая коррекция неправильно введённых команд также может показаться нелишней, хотя это и спорный вопрос:

set correct = cmd

В этом случае, если оболочка воспримет некую команду (из числа определённых в переменной path), как введённую с ошибкой, то предложит корректирующий вариант, с которым можно согласиться (y), проигнорировать (n), вызвать команду для редактирования (e) или оборвать её исполнение с возвратом приглашения командной строки (a).

Для опции correct возможны и другие значения. Так, если определить

set correct = complete

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

Если же переменную correct определить в виде

set correct = all

то вариант исправления ошибок будет предлагаться не только для команд, как при значении cmd, но и для имен файлов или путей к ним, если оболочка сочтёт их неправильно написанными. Последнее крайне раздражает при операциях создания и копирования файлов и каталогов. А поскольку в tcsh, в отличие от zsh, задать исключения для опции correct нельзя, я значением all для неё не пользуюсь.

Следующие переменные имеют отношение к истории команд. Поскольку файл ~/.tcshrc считывается только при работе этой оболочки в интерактивном режиме, необходимости предварять их условным оператором я не вижу. Значения переменных

set history = 1000
set savehist = 1000

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

А вот от балласта в виде дубликатов команд в файле истории целесообразно избавиться — не столько из экономии, сколько ради собственного удобства. Сделать это можно путем определения переменной histdup тремя различными способами, в зависимости от её возможных значений. При значении

set histdup = prev

текущая команда, которая совпадает с последней, имеющейся в файле истории, к файлу истории добавлена не будет.

Установка

set histdup = all

повлечёт за собой сохранение в файле истории только уникальных команд. Оба эти значения переменной histdup вызывают перенумерацию списка команд в файле истории так, чтобы в нём не было никаких «прорех».

После установки

set histdup = erase

перенумерации команд не происходит: последняя введённая команда подменяет собой ранее существовавший её дубликат.

По умолчанию, как уже говорилось, буфер истории команд сохраняется в файле ~/.history. Однако определив переменную histfile, можно дать ему произвольное имя. Это бывает полезно, если tcsh используется попеременно с другими оболочками, файл истории команд которых имеет по умолчанию то же имя — ~/.history.

Ранее говорилось о конфигурационном файле ~/.cshdirs, но не рассказывалось о том, откуда берётся его содержимое. Так вот, в него при выходе из сеанса tcsh записывается путь к последнему текущему каталогу — для этого надо определить переменную

set savedirs

После этого в следующем сеансе регистрационного шелла этот каталог станет текущим при запуске.

Последняя необходимая нам переменная определяет вид первичного приглашения командной строки. Для меня удобна следующая форма:

set prompt = '%~%-> '

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

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

bindkey "^W" backward-delete-word
bindkey -k up history-search-backward
bindkey -k down history-search-forward

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

На этом можно закончить настройку пользовательского файла ~/.tcshrc. Аналогичный конфиг администратора (/root/.tcshrc) можно построить аналогично, с некоторыми отличиями.

Так, в число значений переменной path необходимо добавить все каталоги /path2/sbin, после чего соответствующая строка примет следующий вид:

set path = (/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin)

Ну и приглашение командной строки в сеансе администратора целесообразно сделать отличным от обычного пользовательского:

set prompt = '%~#-> '

Таким образом определяется так называемое первичное приглашение командной строки. Но tcsh позволяет настроить вид вторичного (prompt2) приглашения, выводимого при переходе команды на новую строку после символа \, и третичного (prompt3) приглашения — того самого, которое выводится при предложении коррекции неправильно введённой команды.

Разнообразные виды приглашений можно посмотреть здесь.

В заключение — пара слов о том, что можно внести в файл ~/.logout. Во-первых, можно вообще обойтись без него. А можно вписать в него нечто вроде таких строк:

sync
clear

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

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

Можно также воспользоваться возможностями, предлагаемыми конфигурационными файлами из пакета tcshrc, о котором я говорил в начале этого очерка. Устанавливать их, что называется «в лоб», как это предлагается инсталляционным сценарием, я бы не стал: конфиги эти многочисленны и содержат много избыточных, на мой взгляд, параметров, в частности, бессчётное число псевдонимов команд на случай опечаток. Однако из внимательного рассмотрения этих конфигов и комментариев в них можно почерпнуть немало полезной информации, которую не грех использовать в конфигах собственных.