О блоге

Все новые материалы размещаются на Блогосайте alv.me. Старые - в процессе переноса.

05.08.2008

C-shell и tcsh

Citkit, 2 августа 2005 г

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

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

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

$ ls -l /bin/csh /bin/tcsh

выводящей идентификаторы файлов:

25107 /bin/csh*  25107 /bin/tcsh*

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

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

Различия в синтаксисе между семействами sh и csh отражают различие их обращения с условными выражениями. В классических POSIX-шеллах это - просто последовательности команд (подобные конвейерам), в которых выполнение каждой последующей определяется успешным или неуспешным завершением предыдущей. В 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. Кроме того, есть еще файл истории команд - ~/.history, который образуется и заполняется автоматически.

Как пример настройки, могу привести прокомментированное содержимое своих пользовательских dot-файла для tcsh. Файл ~/,cshrc у меня выглядит примерно так:

# .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 = (/bin /usr/bin /usr/local/bin /usr/X11R6/bin)
# Определение путей к исполняемым файлам
# В конфиге root'а здесь следует указать также
# /sbin /usr/sbin /usr/local/sbin

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

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

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

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

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

# Переменные для интерактивных экземпляров 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

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

# .login - конфиг пользовательской оболочки
# считывается при авторизации, после .cshrc

setenv LANG ru_RU.CP1251
# установка локали

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

setenv BLOCKSIZE K
# единица измерения блоков (килобайты)

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