Это довольно старая заметка, не утратившая, однако, актуальности. Нужно только помнить, что со времени её написания zsh приобрёл много дополнительных полезных свойств, среди которых: средства автоконфигурирования, поддержка UTF8 и многие другие. В настоящее время готовится расширенная и актуализированная версия этого сочинения.
Содержание
- Представление главного героя
- Приступаем к установке
- Начинаем настройку
- Личный рецепт приготовления
- Заключительные замечания
Представление главного героя
Как можно догадаться из названия заметки, главным героем ее является командная оболочка Z-Shell или, сокращенно, zsh
, о которой на протяжении всего предшествующего повествования не было сказано ни слова. Настало время исправить это упущение.
Итак, zsh
- оболочка из клана sh-совместимых, первоначально разрабатывавшаяся Паулем Фальстадом (Paul Falstad), ныне развивается в рамках самостоятельного проекта сообществом энтузиастов (Zsh Development Group) при координации Петера Стефенсона (Peter Stephenson). В отличие от bash
, прямого (как, впрочем, и косвенного) отношения к GNU zsh
не имеет, распространяется под собственной лицензией BSD-стиля, а, следовательно, является полностью свободной программой.
Существует мнение (и не только мое), что в zsh
нашли свое воплощение все прогрессивные тенденции таких развитых оболочек, как bash
и tcsh
. И, ознакомившись с его возможностями, с этим трудно не согласиться - в zsh
есть все, что было хорошего в тех обеих оболочках, но, если так можно выразиться, в превосходной степени.
Действительно, какими особенностями определяется в первую очередь удобство интерактивной работы в командной оболочке? В порядке, котором с ними сталкивается пользователь, это будут:
- автодополнение командной строки;
- возможности навигации по ней и ее редактирования;
- просмотр буфера истории команд;
- возможность минимизации ввода за счет использования псевдонимов.
Автодополнением клавишей Tab команд, частично введенных в ответ на приглашение оболочки, трудно удивить пользователей bash
или tcsh
. Столь же естественно, что при возможности безальтернативного дополнения именно оно и происходит, а при наличии некоторых альтернатив выводятся возможные варианты. Однако zsh
идет дальше - и после вывода таковых в ответ на последующие нажатия клавиши табулятора начинает автоматический их перебор.
Автодополнение путей к файлам, выступающим в качестве аргументов команд, - тоже не бог весть какое новшество. И единственное отличие zsh
от прочих оболочек выражается здесь в том, что и для путей действует автоматический перебор вариантов клавишей табулятора. А вот то, что автодополнение работает также и для аргументов команд, например, команды man
- окажется приятной неожиданностью. Так, чтобы вызвать полное экранное руководство по zsh
, достаточно набрать
$ man zsha
и нажать табулятор, чтобы развернуть его до полного
$ man zshall
Более того, автодополнению (и автоматическому перебору его возможностей) подвержены даже опции многих команд. Это особенно показательно для таких синтаксически сложных команд, как find
. Так, последовательность
$ find / -na
будет автоматически дополнена до
$ find / -name
А после указания этого для указания опции действия можно ограничиться вводом символа дефиса
$ find / -name filename -
и выбрать необходимое действие из предложенного списка, Например, print
- вывод на экран, или exec
- исполнение сторонней команды.
И еще один частный случай автодополнения уникален для zsh
: развертывание путей при сокращенном их наборе. Так, что просмотреть содержимое каталога /usr/portage/distfiles
, достаточно набрать в командной строке
$ ls /u/p/di
и нажать клавишу табуляции: сокращенный ввод пути (разумеется, при безальтернативности оного) будет автоматически развернут до полного.
Автодополнение в zsh
гармонично сочетается с автокоррекцией (т.н. spelling командной строки). Конечно, и это само по себе не уникально. Однако проверка правильности ввода и автокоррекция в zsh
распространяются не только на встроенные (как в bash
) и даже внешние (как в tcsh
) команды, но даже на пути и аргументы. Причем если автокоррекция становится назойливой (например, для команд типа cp
или mv
она порывается исправить аргументы на имена существующих файлов), ее можно отключить - и именно только для определенных команд.
Средства навигации по командной строке и ее автоматического редактирования - необходимое условие комфорта в интерактивной работе внутри оболочки. Здесь говорить, казалось бы, не о чем - управляющие клавишные последовательности для таких действий давно уже вошли в обиход всех командных оболочек, претендующих на развитость. Однако и в этой области zsh
есть чем похвастаться - в нем задействованы все комбинации клавиш для перемещения и удаления (как посимвольного, так и командными "словами" и фрагментами строки), которые существуют в bash
и tcsh
, причем - построенные по тем же принципам.
Управляющие последовательности в zsh
построены по принципу сочетания клавиши Control+литера или Meta+литера, причем вторая комбинация обычно выступает в качестве "усиленного" варианта первой. Так, если Control+D удаляет символ в позиции курсора, то сочетание Meta+D проделывает это для всех символов от позиции курсора до конца командного слова.
Предусмотрены в zsh
и клавишные комбинации для таких действий, как преобразование регистра литерных символов, "перетасовки" символов и командных "слов" в строке, заключения строки в кавычки (а при необходимости - и экранирования оных символами обратного слэша). Есть, конечно же, и комбинация для многоуровневой отмены ввода.
Действие большинства простых (двухклавишных) последовательностей дублируется "сложными", вида Meta+литера-Control+литера, которые прекрасно работают и при переключении на кириллическую раскладку клавиатуры.
Легко заметить, что управляющие последовательности в zsh реализованы с стиле emacs
. Однако это - лишь один из возможных режимов, тот, который принят по умолчанию. При желании ничего не стоит переключить навигацию и управление в режим vi
, если таковой кажется более привычным для пользователя.
Оболочка zsh
обладает всеми стандартными средствами доступа к буферу истории команд - перехода к началу и концу буфера истории, просмотра оного вперед и назад (как клавишами управления курсором, так и соответствующими управляющими последовательностями), обычного и т.н. наращиваемого поиска в обоих направлениях, исполнения выуженной из буфера команды с автоматическим переходом к следующей. Плюс - весьма изощренные способы вывода в строку отдельных фрагментов команд из буфера истории - например, отдельного командного "слова", начиная с последнего, с дальнейшим перебором "слов" буферизованных команд назад. Или - вывод полного списка команд из буфера с их последовательным перебором в том или ином направлении.
И, наконец, такое мощное средство минимизации пользовательского ввода, как псевдонимы команд (aliases). Разумеется, в zsh
(как и в bash
или tcsh
) псевдоним может быть присвоен любой команде со сколь угодно длинным набором опций. Так, куда как проще раз и навсегда определить команду ls
как псевдоним самой же себя, но с опциями -FG
, нежели каждый раз вспоминать, как отличить в ее выводе каталоги от обычных файлов.
Однако zsh
идет дальше: в нем это дополняется возможностью определения псевдонимов для командных конвейеров в форме опции -g
(от global aliases - именно так именуется эта возможность). Так, всем известно, что для обеспечения постраничного вывода любой команды (например, той же ls
) вывод этот нужно передать по конвейеру (pipe) программе-pager'у (less
или more
). Однако не лениво ли - каждый раз вводить что-нибудь вроде
$ ls | less
да еще и не забывать это делать? Если лениво - на помощь придут глобальные псевдонимы. Опять же раз и навсегда определяем, что опция -g
со значением L
есть псевдоним для конвейера '| less'
:
$ alias -g L='| less'
после чего имеем возможность, указывая ее после команды, требующей постраничного ввода, именно его и получать:
$ ls -g L
Казалось бы, не намного проще? Ан нет: ведь ничто не препятствует нам создать еще один, обычный, псевдоним для команды ls
с этой опцией, например:
$ alias lp='ls -g L'
чтобы при необходимости постраничного вывода списка каталога именно к нему и прибегнуть.
Важный момент облегчения существования пользователя в любом шелле - вид приглашения командной строки, должная настройка которого может часто избавить от лишнего набора команд (уж от команды pwd
я по возможности стараюсь избавиться именно таким образом). Так вот, zsh
поддерживает несколько независимо настраиваемых обычных приглашений - обычное, или первичное, вторичное - для многострочных команд, "выделенное", приглашение при выводе вариантов автокоррекции и даже специальное "приглашение" в правой части командной строки. Которое, конечно, собственно приглашением не является, но позволяет вывести полезную информацию, например, текущее время или дату, номер виртуальной консоли, и т.д. Для пущей экспрессии настраивается также передача символов в любом приглашении - цветом ли, выделением, инверсией, подчеркиванием.
Очень полезная возможность - различение вида приглашения для обычного пользователя, получившего права root'а в результате команды su
без опций (то есть без перечитывания профильных файлов администратора), от собственно пользовательского приглашения - дабы не забывал юзер о временности своих полномочиях.
Надеюсь, что мне удалось убедить читателя в превосходных интерактивных возможностях оболочки zsh
. Теперь стоит поговорить о функциональности, которая проявляется не только в интерактивной работе (но и, скажем, при сочинении скриптов). Функциональность же любой оболочки можно в первом приближении оценить по количеству встроенных в нее команд. То есть - команд, выполняемых внутри самого шелла, без порождения новых процессов, как это происходит при выполнении внешних команд. Очевидно, что такие встроенные команды будут выполняться быстрее и отъедать меньше ресурсов. Что, конечно, не скажется при интерактивной работе на современных машинах, но вот в сложных сценариях - вполне может.
В zsh
поддерживается весь набор встроенных команд, стандартизированный для POSIX shell, большинство команд из развитых оболочек bash
и tcsh
, ну и, разумеется, специфичные для этого шелла команды. Общее число их превышает 80 - примерно столько же, сколько встроено в tcsh и bash, вместе взятые.
Очень интересна (и удобна) в zsh
работа с командными конструкциями перенаправления. Здесь и множественное перенаправление вывода, когда результат выполнения команды направляется сразу в несколько файлов, и множественное перенаправление ввода - когда команда, напротив, получает аргументы последовательно из более чем одного файла, перенаправление без команды, когда конструкция типа
$ <>
просто выведет на экран содержимое указанного файла - без привлечения команд типа cat
или less
.
При перенаправлении возможна группировка команд по шаблону. Так, файлы с именами вида file1
и file2
можно просмотреть одной командой
$ <>
Перенаправление ввода/вывода может иногда заменять конвейеризацию команд. Так, конструкция вида
$ sort <>
отсортирует содержимое обоих файлов точно так же, как это сделал бы конвейер команд
$ cat file1 file2 | sort
Наконец, еще одна специфическая особенность zsh
- т.н. пред-исполнимая модификация команд (precommand modifier), осуществляющаяся перед их интерпретацией. Именно таким образом можно отменить чрезмерно навязчивую автокоррекцию аргументов для одной отдельно взятой команды, например, копирования:
$ nocorrect cp file1 file2
Легко видеть, что все изобилие возможностей zsh
далеко выходит за рамки стандарта POSIX для командных оболочек. Однако, в подтверждение своего соответствия оному, zsh
, наступая на горло собственной песне, способен к эмуляции POSIX Shell - для этого достаточно создать файл /bin/sh
как символическую ссылку на исполнимый файл zsh
, например:
$ ln -s /usr/bin/zsh /bin/sh
Впрочем, делать это следует только в случае полной уверенности, что все общесистемные скрипты полностью совместимы с zsh
- а такая уверенность может быть только в том случае, если они написаны собственноручно:-). Я успешно применял zsh
в качестве общесистемного шелла в самостройном Linux'е (по мотивам Linux from Scratch). Однако в других дистрибутивах (и тем более во FreeBSD) от этого лучше воздержаться.
Кроме того, имеется и некий режим совместимости с командными оболочками csh-клана (в нем я, впрочем, не разбирался).
Здесь перечислена лишь небольшая часть возможностей оболочки zsh
, в частности, я не останавливался на его встроенных функциях, хотя именно они и есть та база, что обеспечивает все описанное (и не описанное) богачество возможностей. Не говорил я и о подгружаемых модулях (по типу plug-ins) - а ведь среди последних есть даже собственный ftp-клиент. Ибо для этого потребовалось бы пересказать всю экранную документацию к нему - более дюжины man-страниц общим объемом (в *.gz-виде) свыше 250 Кбайт, плюс официальное руководство с сайта проекта, включающее в pdf-формате 260 страниц (к слову - автором этой документации является тот же Петер Стефенсон).
Тем не менее надеюсь, что я убедил вас в том, что zsh
- штука стоящая. Если так - то
Приступаем к установке
Оболочка zsh
стандартно входит в большинство (я бы сказал - во все из мне известных) полнофункциональных дистрибутивов Linux, в качестве портов и пакетов доступна во Free- и OpenBSD (на счет NetBSD - просто не помню), портирована даже в AtheOS (вернее - ее отпрыска Syllable). Так что проблем с ее получением быть не должно. Устанавливаем zsh
штатным для данного дистрибутива методом и переходим к следующему разделу.
Если же почему-либо zsh
в составе дистрибутива не обнаружился - отправляемся на ftp://ftp.zsh.org/pub/ или какое-либо его зеркало (список - на hcodep://www.zsh.org), можно - в каталог distfiles
ftp-серверов FreeBSD или Gentoo. И качаем в свое удовольствие исходники последней стабильной версии (на данный момент - 4.07), или, при желании, разрабатываемой (ныне - 4.2) - различий в стабильности между ними я не заметил.
Исходники zsh
распаковываются и собираются обычным образом - ./configure
, make
, make install
, никаких неожиданностей здесь не предвидится. Единственно, я предварительно, чисто для интереса, поинтересовался бы опциями конфигурирования -
$ ./configure --help
Из которых не побрезговал бы опцией --bindir=/bin
- это будет полезно, если zsh
будет использоваться как login shell.
В дистрибутивах Linux, предусматривающих автоматическое обновление общесистемных профильных файлов (например, в Gentoo), может возникнуть необходимость в том, чтобы zsh
брал свои переменные окружения из какого-либо общего конфига, например, /etc/profile
. Для этого при начальном конфигурировании исходников следует указать
$ ./configure --enable-zprofile=/etc/profile
И еще: ручная сборка zsh
может потребоваться в некоторых пакетных дистрибутивах, в которых, будучи установленным из бинарников, он может работать неподобающим образом (о причинах я скажу позже).
Теперь же, установив zsh
тем или иным образом, делаем его своей пользовательским шеллом по умолчанию - login shell (одной из команд типа usermod
, pw
, chsh
) и -
Начинаем настройку
Без этого нам, скорее всего, не обойтись. Дело в том, что в свежеустановленном zsh
, мы имеем шанс не увидеть почти ничего из описанных выше прелестей - ни развертывания сокращений путей, ни автодополнений опций и аргументов, ни выразительных приглашений командной строки. Перед нами будет безликая строка с именем машины (типа localhost%
), которая едва-то будет справляться с обычным автодополнением команд и путей (и то - не обязательно). Могут возникнуть проблемы даже с вызовом собственной экранной документации man zsh
. Почему?
Дело в том, что zsh
имеет очень богатый набор собственных конфигурационных файлов, о которых я скажу чуть ниже. Но при установке его эти файлы не помещаются автоматически ни в каталог /etc
, ни в домашний каталог пользователя - то есть ни в одно из тех мест, где их можно было бы ожидать. Конечно, совсем без первичных настроек zsh
не останется: он прекрасно воспринимает их из таких общесистемных профильных файлов, как /etc/profile
, /etc/login
и т.д. Однако, во-первых, для этого он должен быть собран должным образом. А во-вторых, и вести себя при этом он будет почти точно также, как и соответствующие оболочки (bash
или tcsh
, а то и /bin/sh
- почему, например, во FreeBSD zsh по первости не способен даже к автодополнению команд). От одного из этих профильных файлов zsh
унаследует и переменные окружения, включая MANPATH
- почему подчас не сможет найти и свою собственную документацию.
Так что для придания zsh
полного блеска следует прибегнуть к его собственным конфигурационным файлам. Правда, сначала придется отыскать их примеры из штатной поставки - должен заметить, что в разных системах они могут обнаружиться в весьма неожиданных местах. Так, во FreeBSD их штатное место - каталог /usr/local/share/examples/zsh
, в дистрибутиве Gentoo Linux примеры оказываются в /usr/share/doc/zsh-XXX-rX/StartupFiles
, в иных - вполне могут оказаться где-нибудь в районе /usr/share/zsh
, и т.д.
Для минимизации времени на поиски выдам секрет - примеры конфигурационных файлов zsh
, входящие в штатный комплект, называются - zlogin
, zshenv
и zshrc
(возможно, с расширением .gz
), и благодаря моей доброте :-) их не трудно будет отыскать командой find
- за пределы каталога /usr
файлы эти попасть не должны (даже в том случае, если, как в Gentoo, сам исполняемый файл zsh
оказывается в каталоге /bin
).
После изыска конфигов для сердца вольного есть два пути. Первый - простой, копируем их в наш домашний каталог в качестве dot-файлов (~/.zlogin
, ~/.zshenv
и ~/.zshrc
, соответственно), после чего наслаждаемся жизнью. В ряде случаев этого достаточно, чтобы получить доступ к базовым (но очень даже расширенным, сравнительно с собратьями) возможностям этого шелла.
Разумеется, суперпользователь может скопировать эти файлы и в каталог /etc
(без точек в имени) - в этом случае они будут определять конфигурацию zsh
для всех пользователей, его запускающих (любым образом, о чем - чуть ниже).
Второй путь - попытаться разобраться, за что отвечают скопированные файлы и как они устроены. Это понадобится в двух случаях - а) для идеальной настройки своего нового шелла и б) если zsh
работает не совсем так хорошо, как вы ожидали (например, не так, как описано выше).
Первый шаг на этом пути - задаться вопросом, а зачем zsh
'у так много конфигов, если другие шеллы спокойно обходятся двумя (а то и одним, как /bin/sh
). На это я отвечу, что конфигов в zsh
вовсе не много, а очень много: в дополнение к трем примерным в разделе FILES его man-страницы можно найти упоминание еще о zprofile
и zlogout
(и, соответственно, ~/.zprofile
и ~/.zlogout
). А в ходе пользования им вы, скорее всего, увидите в своем каталоге еще и такие файлы, как ~/.zcompdump
и ~/.zhistory
.
Так для чего нам такое богачество? Чтобы разобраться в этом, вспомним о трех видах функционирования любого шелла - неинтерактивном, интерактивном и подвиде последнего - главном пользовательском (login shell
). Так вот, файл /etc/zshenv
(или ~/.zshenv
) считывается при каждом запуске любого экземпляра zsh
, независимо от того, происходит он интерактивно или опосредованно. Настройки файла /etc/zshrc
(и ~/.zshrc
) имеют силу для любого интерактивного запуска zsh
. И, наконец, файлы /etc/zlogin
и /etc/zprofile
оба вместе (как и соответствующая им пара ~/.zlogin
и ~/.zprofile
) относятся только к тому экземпляру интерактивно запущенного zsh
, который выступает в качестве login shell
.
Зачем так сложно? А для того, чтобы можно было гибко (и индивидуально) настроить неинтерактивные, интерактивные и пользовательские экземпляры шеллов. Действительно, очевидно, что на настройку неинтерактивного шелла влияет только содержимое файла /etc/zshenv
(и ~/.zshenv
), на настройку любого интерактивно запущенного экземпляра - уже он же вкупе с /etc/zshrc
(и ~/.zshrc
), тогда как поведение login shell
определяется кумулятивным эффектом всех трех (или даже четырех) их пар.
Хорошо, но зачем же нам два конфига для login shell
? - спросите вы меня. Ответ прост - из соображений совместимости с bash
и tcsh
. Для пояснения чего вернемся к истории вопроса. В первозданном шелле Борна существовал только один конфиг - /etc/profile
(~/.profile
) для любых экземпляров шелла. В bash
к нему прибавился еще и файл /etc/bashrc
(~/.bashrc
) для интерактивного использования (считываемые, естественно, после предыдущего - как более молодой по происхождению).
В csh
же набор конфигов был совсем иной. Там изначально существовали два конфига - /etc/csh.env
(~/.csh.env
) на все случаи жизни и /etc/login
(~/.login
) - в качестве конфигуратора login shell
, считываемые именно в таком порядке.
В zsh же, дабы удовлетворить привычки пользователей любых предшествовавших шеллов, были включены оба "логируемых" конфига, причем порядок их считывания был унаследован от каждого из родителей. В результате получилась довольно сложная последовательность при запуске login shell
:
zshenv -> zprofile -> zshrc -> zlogin
Причем каждый конфиг сначала, естественно, считывается из каталога /etc
, а затем из домашнего каталога пользователя берется его аналог. Разумеется, если все четыре файла присутствуют (и там, и там). Что, сразу скажем, отнюдь не обязательно. Очевидно, что совместное использование zprofile
и zlogin
ни малейшего смысла не имеет. Просто бывшим пользователям bash
привычней первая схема запуска login shell
, бывшим приверженцам tcsh
- вторая. Забегая вперед, замечу, что вообще пользователь может обойтись только одним конфигом в своем домашнем каталоге (например, ~/.zshrc
для любого интерактивного экземпляра шелла - ведь login shell
также будет интерактивным), а все общие настройки получать из общесистемного конфига (например, /etc/profile
). Более того, в дистрибутиве Gentoo Linux именно так поступить лучше всего - к причинам вернусь позднее.
Осталось объяснить смысл остальных dot-файлов из пользовательского каталога. Каковой, впрочем, ясен из названий:
- это сценарий, отрабатываем при выходе из ~/.zlogout
login shell
, ~/.zhistory
хранит историю команд (это и есть ее буфер), а ~/.zcompdump
(насколько я понимаю) - делает то же самое, но для встроенных функций zsh
. Два последних файла возникают (при выполнении некоторых условий) сами собой, и речи о них больше почти не будет.
Разобравшись с назначением dot-файлов, можно, наконец, выполнить
Собственно конфигурирование
Процесс этот начнем с того, что отделим зерна от плевел, то есть решим: а какие же именно файлы нужно настроить. Для начала я оставил бы в покое все файлы из каталога /etc
- вернее, просто не стал бы копировать туда примеры. Почему? Да потому, что во многих дистрибутивах Linux имеются либо предварительно настроенные общесистемные конфиги, либо предусмотрены средства для их автоматического создания и обновления (ниже я продемонстрирую это на примере Gentoo). А во FreeBSD в каталоге /etc
принято хранить только профильные файлы общесистемного шелла (сиречь /bin/sh
, тогда как настройка пользовательского шелла - сугубо личное дело пользователя.
Так что ограничиваемся только нашим домашним каталогом. Однако и здесь многое зависит от ОС и дистрибутива. Так, в user-ориентированных дистрибутивах Linux первый кандидат на удаление (или не-копирование) - файл ~/.zshenv
. Конечно, его можно создать в предельно облегченном виде (например, настройка приемов неинтерактивной работы здесь абсолютно лишняя). Характерно, что в штатном примере zshenv
присутствует только переменная PATH
. Но ведь ее можно получить из общесистемного /etc/profile
, не так ли?
Особенно лишним выглядит ~/.zshenv
для пользователей Gentoo. Как можно прочитать в соответствующей документации, здесь существует прекрасный механизм установки общесистемных переменных - env-update
, автоматически обновляющий главный профильный конфиг /etc/profile
. Так что при отсутствии ~/.zshenv
все необходимое (в актуальном виде) будет браться оттуда. В присутствии же его - zsh
откажется от считывания /etc/profile
, в результате чего такие переменные, как локаль, EDITOR
, PAGER
и т.д., придется определять дополнительно.
А вот во FreeBSD и тех дистрибутивах Linux, которые (как, например, CRUX и Archlinux) не имеют средств автоматизации установки общесистемных переменных, файл ~/.zshenv
оказывается практически необходимым. И ниже я попытаюсь обосновать это (а заодно и продемонстрировать, что в нем может содержаться).
Далее, решаем, а нужен ли нам отдельный конфиг для login shell
, и если нужен - то какой из них - ~/.zlogin
или ~/.zprofile
. Теоретически, можно обойтись и без того, и без другого. Уж без последнего - так наверняка, не зря же его нет ни среди штатных примеров, ни среди многочисленных конфигов, которыми поделились с народом активные пользователи zsh
(см. источники информации). А файл ~/.zlogin
у меня, например, есть, хотя содержание его может варьировать от системы к системе.
Не помешает и файл ~/.zlogout
- его возможное содержание также будет рассмотрено позднее.
Остается главный (по крайней мере, самый большой) конфиг - ~/.zshrc
. Что с ним делать? Это легко уяснить, ознакомившись со штатным примером.
А в примере этом мы найдем и настройку приглашений командной строки, и определение псевдонимов - обычных и глобальных, для конвейеров команд, и определение переменной cdpath
, и величину буфера истории команд, и многое, многое другое.
Описывать все опции из примера было бы долго и скучно. А потому здесь я остановлюсь только на тех, которые создают удобство при интерактивной работе и определяют внешний вид нашего шелла.
Начнем с последнего, то есть приглашения командной строки. В этом качестве могут использоваться:
- полное или сокращенное имя хост-машины (последнее принято по умолчанию для первичного);
- путь к текущему каталогу в различных формах;
- номер текущей команды в буфере истории или строки в данном сеансе работы;
- имя пользователя, или командной оболочки;
- номер текущего терминала;
- дата и время в разных форматах;
- индикация работы от лица суперпользователя);
- любые символы типа стрелок, крышечек, скобочек;
- текстовые сообщения (например, поздравление с началом трудового процесса);
- многое другое (подробности - в man zshhmisc).
Плюс к этому приглашения могут быть оформлены визуально различно: выделением жирным шрифтом (boldface mode) или повышенной яркостью (underline mode), инвертированием текста/фона (standout mode), а также цветами. Все это позволяет добиться максимальной информативности приглашения и его внешней выразительности.
Из опций настройки интерактивности - вспомним о том, что обеспечивает расширенные возможности автодополнения. А обеспечиваются они строками, следующими после комментария:
# Setup new style completion system. To see examples of the old style (compctl
# based) programmable completion, check Misc/compctl-examples in the zsh
# distribution.
и имеющими вид
autoload -U compinit
compinit
Вообще, штатный пример файла zshrc
очень неплохо прокомментирован - по аглицки, но разобраться можно:-).
Далее - опции управления историей команд. Здесь для начала следует определить файл, в котором эта история будет храниться (в примере по умолчанию таковой отсутствует, и никакая история по умолчанию не сохраняется по выходе из сеанса zsh
):
HISTFILE=~/.zhistory
Теперь - объем нашей исторической памяти, задаваемый двумя опциями -
HISTSIZE=1000
определяющей память текущего сеанса, и
SAVEHIST=1000
устанавливающая размер буфера, сохраняемого в HISTFILE
. Очевидно, что первую бессмысленно делать больше второй (рекомендуются равные значения - в моем примере они взяты просто с потолка).
Для обеспечивая наращивания файла истории после каждого сеанса работы (в пределах установленной квоты) определяем:
setopt APPEND_HISTORY
Объем исторической памяти можно установить любым, однако не стоит расходовать его на повторение дублирующихся команд, ошибочными нажатиями Enter в пустой строке и т.д.:
setopt HIST_IGNORE_ALL_DUPS
setopt HIST_IGNORE_SPACE
setopt HIST_REDUCE_BLANKS
Можно настроить и еще много чего, но на этом пока закончим (некоторые опции будут подробнее рассмотрены в следующем разделе). Потому что наступило время подумать, а что представляют из себя установленные нами опции (типа compinit
и т.д.)? А представляют они собой по преимуществу встроенные функции из комплекта zsh
, которые в изобилии можно обнаружить в каталоге /usr/share/zsh/4.0.6/functions
. И именно благодаря этим функциям и удается все настроить.
А еще - становится понятным, почему иногда zsh
в пакетных дистрибутивах, устанавливаясь из бинарников, ведет себя не вполне подобающим образом. Да именно потому, что комплект функций в поставке и их использование в файлах примеров не вполне идентичны (по крайней мере, мне такие случаи встречались). При сборке же из исходников с сайта проекта, насколько мне довелось наблюдать, идентичность эта гарантирована. Тот же результат, естественно, достигается и в Source Based дистрибутивах (или, скажем, в системе портов FreeBSD).
Вообще говоря, я долго не мог понять, почему пользователи не любят zsh
. И в конце концов пришел к выводу - именно потому, что сборщики дистрибутивов подчас не умеют его готовить. Это - не только мое мнение: многие пользователи пакетных дистрибутивов свидетельствуют, что установленный из "коробки" zsh
в их системах работает весьма криво. Так что позволю себе привести
Личный рецепт приготовления
Как-то на одном форуме промелькнул вопрос - а как сделать, чтобы в командной строке zsh
клавиши типа Delete, End, Home вели себя нормально (по умолчанию они этого делать не собираются). У меня до этого долго не доходили руки - я в этих целях привык к клавишным комбинациям (см. следующий раздел). Однако некоторое чувство дискомфорта преследовало: как же так, какой-то там bash
умеет нормально обращаться с клавишами, а любимый zsh
- не умеет. А тут и случай представился: во время затеянной в рамках мегатестирования тотальной пересборки Qt/KDE/иже_с_ними времени образовалось - вагон и маленькая тележка. И я наконец-то разобрался с клавишами в zsh
. О чем с удовольствием рапортую в этом разделе.
Из многочисленных zsh-конфигов я (в настоящее время) использую: ~/.zshenv
, считываемый при каждом запуске экземпляра оболочки (интерактивном и неинтерактивном), ~/.zshrc
, считываемый при каждом интерактивном ее запуске, и ~/.zlogin
, считываемый при каждом запуске zsh
в качестве login shell
. При этом установка переменных окружения происходит в стиле C-Shell: сначала из ~/.zshenv
, затем из ~/.zshrc
и, наконец, из ~/.zlogin
.
Так что первым в моей схеме идёт ~/.zshenv
. Он оказывает воздействие только при shell-скриптинге. Поэтому у меня он очень мал. В Linux-варианте (для Archlinux) он выглядит так:
#
# My ~/.zshenv for Linux
#export PATH="/bin:/usr/bin:\
/usr/local/bin:/usr/X11R6/bin:\
/opt/bin:/opt/kde/bin"
Во FreeBSD все примерно то же, но, естественно, /opt
в PATH
включать не требуется:
#
# My ~/. zshenv for FreeBSD
#
PATH="/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin"
QTDIR=/usr/local/qt
PATH="$PATH:$QTDIR"
MANPATH="$QTDIR/doc/man:$MANPATH"
LD_LIBRARY_PATH="$QTDIR/lib:$LD_LIBRARY_PATH"
export QTDIR PATH MANPATH LD_LIBRARY_PATH
Понятно, что оба файла можно записать поизящней (с точки зрения формы), но - так уж они исторически склались.
Основное внимание я уделяю файлу ~/.zshrc
, так как им определяется поведение zsh
не только при авторизации в консоли, но и при запуске терминальных окон в Иксах.
#
# My ~/.zshrc
#
# Path для поиска командой cd: то есть вместо cd $HOME/docs/editors/
# можно набирать просто cd editors
cdpath=(~/media ~/docs)
## Установка нормального поведения клавиш Delete, Home, End и т.д.:
case $TERM in
linux)
bindkey "^[[2~" yank
bindkey "^[[3~" delete-char
bindkey "^[[5~" up-line-or-history
bindkey "^[[6~" down-line-or-history
bindkey "^[[1~" beginning-of-line
bindkey "^[[4~" end-of-line
bindkey "^[e" expand-cmd-path ## C-e for expanding path of typed command
bindkey "^[[A" up-line-or-search ## up arrow for back-history-search
bindkey "^[[B" down-line-or-search ## down arrow for fwd-history-search
bindkey " " magic-space ## do history expansion on space
;;
*xterm*|rxvt|(dt|k|E)term)
bindkey "^[[2~" yank
bindkey "^[[3~" delete-char
bindkey "^[[5~" up-line-or-history
bindkey "^[[6~" down-line-or-history
bindkey "^[[7~" beginning-of-line
bindkey "^[[8~" end-of-line
bindkey "^[e" expand-cmd-path ## C-e for expanding path of typed command
bindkey "^[[A" up-line-or-search ## up arrow for back-history-search
bindkey "^[[B" down-line-or-search ## down arrow for fwd-history-search
bindkey " " magic-space ## do history expansion on space
;;
esac
# Примечание: если, скажем, в KDE для konsole
# выбрать тип Linux console, необходимости
# во второй секции нет. Консоль Linux в KDE можно
спокойно установить и во FreeBSD.
# К слову сказать, совсем уж нормального
# поведения клавиш в syscons я до сих пор
# не добился:-(
# Use hard limits, except for a smaller stack and no core dumps
unlimit
limit stack 8192
limit core 0
limit -s
# Установка атрибутов доступа для
# вновь создаваемых файлов
umask 022
# Исправление поведения less - для ликвидации
# лишних Esc и прочего безобразия при
# выводе man-страниц.
# Насколько мне известно, нужно только в некоторых
# дистрибутивах Linux
export LESS="-R"
# Установка alias'ов
## alias'ы для команд, не требующих коррекции, но требующих подтверждения
alias mv='nocorrect mv -i'
# переименование-перемещение c пogтвepжgeнueм
alias cp='nocorrect cp -iR'
# рекурсивное копирование с подтверждением
alias rm='nocorrect rm -i'
# удаление с подтверждением
alias rmf='nocorrect rm -f'
# принудительное удаление
alias rmrf='nocorrect rm -fR'
# принудительное рекурсивное удаление
alias mkdir='nocorrect mkdir'
# создание каталогов без коррекции
## Примечание: если не определить здесь nocorrect,
## zsh будет настойчиво предлагать подстановку
## существующих имен при создании каталогов,
## копировании и т.д.
## Разные полезные (ИМХО) alias'ы
alias h=history
alias grep=egrep
### вывод свободного дискового пространства
### в мегабайтах
alias df='df -m'
### Представление вывода less в more-подобном виде
### (с именем файла и процентом вывода)
alias less='less -M'
### Русский словарь для ispell по умолчанию
alias ispell='ispell -d russian'
## aliases для команды ls< ### показ классификации файлов в цвете и ### символически (Linux) alias ls='ls -F --color=auto' ### Во FreeBSD достаточно alias ls='ls -F' ### вывog в gлuннoм фopмaтe alias ll='ls -l' ### вывog всех файлов, включая dot-фaйлы, кромe . u .. alias la='ls -A' ### вывog вcex фaйлoв в gлuннoм фopмaтe, вkлючaя inodes alias li='ls -ial' ### вывод только каталогов alias lsd='ls -ld *(-/DN)' ### вывog тoльko dot-фaйлoв alias lsa='ls -ld .*' # Установка глобальных псевдонимов # для командных конвейеров alias -g M='|more' alias -g L='|less' alias -g H='|head' alias -g T='|tail' alias -g N='2>/dev/null'
# Ниже даны опции, относящиеся к функциям zsh,
# которыми собственно и определяется мощь этой оболочки
# Shell functions
setenv() { typeset -x "${1}${1:+=}${(@)argv[2,$#]}" }
# csh compatibility
freload() { while (( $# )); do; unfunction $1; autoload -U $1; shift; done }
# Where to look for autoloaded function definitions
fpath=($fpath ~/.zfunc)
# Autoload all shell functions from all directories in $fpath (following
# symlinks) that have the executable bit on (the executable bit is not
# necessary, but gives you an easy way to stop the autoloading of a
# particular shell function). $fpath should not be empty for this to work.
for func in $^fpath/*(N-.x:t); autoload $func
# automatically remove duplicates from these arrays
typeset -U path cdpath fpath manpath
# Указание путей к man-страницам.
## Linux:
manpath="/usr/man:/usr/share/man:\
/usr/local/man:/usr/X11R6/man:/opt/qt/doc"
## FreeBSD:
manpath="/usr/share/man:/usr/local/man:/usr/X11R6/man"
export MANPATH
# Список хостов, к которым будет применяться
# автодополнение при наборе в командной строке
# например, как аргументов браузера или
# ftp-клиента (see later zstyle)
hosts=('hostname' ftp.freebsd.org ftp.archlinux.org)
# Установка вида приглашения
## Обычное приглашение вида ~%=>
## (каталог от домашнего - пользователь/root - стрелка)
PROMPT='%~%#=> '
## Приглашения для второй линии многострочных команд
## вида #_строки>
PROMPT2='%i%U> '
## Приглашение с правой стороны экрана вида
## 19:15 vc/5 (время - номер консоли)
RPROMPT=' %T %y%b'
# Всякие переменные
## файл истории команд
## если не указан, история не будет сохраняться
## при выходе из сеанса
HISTFILE=~/.zhistory
## Число команд, сохраняемых в HISTFILE
SAVEHIST=5000
## Чucлo кoмaнд, coxpaняeмыx в сеансе
HISTSIZE=5000
## Примечание:
## рекомендуются равные значения для
## SAVEHIST и HISTSIZE
DIRSTACKSIZE=20
# Опции истории команд
## Дополнение файла истрии
setopt APPEND_HISTORY
## Игнopupoвaть вce пoвтopeнuя команд
setopt HIST_IGNORE_ALL_DUPS
## Игнopupoвaть лишние пpoбeлы
setopt HIST_IGNORE_SPACE
## Удалять из файл истории пустые строки
setopt HIST_REDUCE_BLANKS
# Установка-снятие опций шелла
setopt notify globdots correct pushdtohome cdablevars autolist
setopt correctall autocd recexact longlistjobs
setopt autoresume histignoredups pushdsilent noclobber
setopt autopushd pushdminus extendedglob rcquotes mailwarning
unsetopt bgnice autoparamslash
## Отключение звукового сигнала
## при ошибках
setopt No_Beep
## Нe cчuтaть Control+C зa выxog uз oбoлoчku
setopt IGNORE_EOF
# Autoload zsh modules when they are referenced
zmodload -a zsh/stat stat
zmodload -a zsh/zpty zpty
zmodload -a zsh/zprof zprof
zmodload -ap zsh/mapfile mapfile
# Опции общего поведения
# bindkey -v # режим навигации в стиле vi
bindkey -e # peжuм нaвuгaцuu в cтuлe emacs
bindkey ' ' magic-space # also do history expansion on space
bindkey '^I' complete-word # complete on tab, leave expansion to _expand
# Для разворота сокращенного ввода типа cd d/e в docs/editors
autoload -U compinit
compinit
# Completion Styles
# list of completers to use
zstyle ':completion:*::::' completer _expand _complete _ignored _approximate
# allow one error for every three characters typed in approximate completer
zstyle -e ':completion:*:approximate:*' max-errors \
'reply=( $(( ($#PREFIX+$#SUFFIX)/3 )) numeric )'
# insert all expansions for expand completer
zstyle ':completion:*:expand:*' tag-order all-expansions
# formacodeing and messages
zstyle ':completion:*' verbose yes
zstyle ':completion:*:descriptions' format '%B%d%b'
zstyle ':completion:*:messages' format '%d'
zstyle ':completion:*:warnings' format 'No matches for: %d'
zstyle ':completion:*:corrections' format '%B%d (errors: %e)%b'
zstyle ':completion:*' group-name ''
# match uppercase from lowercase
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
# offer indexes before parameters in subscripts
zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
# command for process lists, the local web server details and host completion
#zstyle ':completion:*:processes' command 'ps -o pid,s,nice,stime,args'
#zstyle ':completion:*:urls' local 'www' '/var/www/htdocs' 'public_html'
zstyle '*' hosts $hosts
# Filename suffixes to ignore during completion (except after rm command)
zstyle ':completion:*:*:(^rm):*:*files' ignored-pacodeerns '*?.o' '*?.c~' \
'*?.old' '*?.pro'
# the same for old style completion
#fignore=(.o .c~ .old .pro)
# ignore completion functions (until the _ignored completer)
zstyle ':completion:*:functions' ignored-pacodeerns '_*'
# Флаги оптимизации для gcc
CFLAGS="-O3 -march=pentium4 -fomit-frame-pointer \
-funroll-loops -pipe -mfpmath=sse -mmmx -msse2 -fPIC"
CXXFLAGS="$CFLAGS"
BOOTSTRAPCFLAGS="$CFLAGS"
export CFLAGS CXXFLAGS BOOTSTRAPCFLAGS
И, наконец, файл ~/.zlogin
. Что осталось неохваченным в ~/.zshrc
и требуется только при авторизации в системе? Правильно, пользовательские переменные для определения терминала, редактора, пейджера и т.д.
#
# My ~/.zlogin for FreeBSD
#
from 2>/dev/null
EDITOR=joe
PAGER=less
TERM=${TERM:-cons25r}
export EDITOR PAGER TERM
Кроме того, в Linux'е здесь же резонно установить locale (во FreeBSD локаль лучше определять через класс пользователя). И потому для Linux - дополнение:
#
# My ~/.zlogin appendix for Linux
#
# Установка всех локально-зависимых переменных,
# кроме LC_ALL
export LANG="ru_RU.koi8r"
# Установка десятичной точки
# вместо запятой
# (требуется для некоторых счетных программ)
export LC_NUMERIC="POSIX"
Да, самое последнее - файл ~/.zlogout
, отрабатываемый по завершении сеанса пользовательского шелла. У меня от включает две строчки
sync
clear
назначение которых более чем понятно (синхронизация дисковых кэшей и очистка экрана).
Это мои пользовательские конфиги. Почти те же самые я использую и для root'а, с минимальными коррективами. Так, переменная path
в /root/.zshenv
дополняется значениями
/sbin:/usr/sbin:/usr/local/sbin
В /root/.zshrc
опция cdpath
имеет вид
cdpath=(/etc /usr)
Кроме того, во FreeBSD здесь я исключаю переменные CFLAGS
, CXXFLAGS
и BOOTSTRAPCFLAGS
, так как от лица root'а все собирается через систему портов, где их аналоги определяются в файле /etc/make.conf
.
А в /root/.zlogin
локаль (в Linux) установлена как
export LANG="POSIX"
так как некоторые программы упорно не желают собираться при какой-либо иной.
Заключительные замечания
Я уже упоминал, что проект zsh
прекрасно документирован, один User's Guide чего стоит. Однако внимание прессы, как онлайновой, так и бумажной, к нему явно недостаточно. И потому из дополнительных источников информации на ум приходит только (если не считать отрывочных упоминаний в паре книжек по Linux) статья Мэтта Чапмена (Macode Chapman) - Curtains up: introducing the Z shell. Да еще недавно появился на русском языке материал Алексея Отта Командный процессор Zsh
Много полезного можно узнать из анализа dot-файлов различных пользователей, ссылки на которые отыскиваются как на www.zsh.org, так и в иных местах. Собирать все эти ссылки мне было лениво (да подчас я и не помню, где их отыскал), так что все свои находки я собрал воедино в виде отдельного тарбалла.