Это начало серии заметок про Z-shell, которую я рассчитываю довести до конца по мере сил и возможностей.
О шеллах вообще
Шелл (Shell), именуемый по-русски командной оболочкой, командным интерпретатором, командным процессором или иными, столь же неизящными словосочетаниями, — это первая программа, с которой сталкивается пользователь любой POSIX-совместимой ОС. И с ним же последним он расстается, выходя из системы. А все его действия во время работы — суть прямые или опосредованные команды, выполняемые в среде шелла. И даже если основная часть работы пользователя проходит в графическом режиме, в окружении интегрированных сред или оконных менеджеров, — окно терминала с приглашением командной строки быстро станет неотъемлемым атрибутом любого десктопа. Ибо именно команды оболочки — самый простой и эффективный путь к выполнению всех операций по управлению файлами, многих задач обработки текста, да и просто запуска любых программ, что в консоли, что — в терминальном окне графического режима.
Кроме того, всегда следует помнить, что вообще функционирование Unix-подобной системы в значительной мере происходит в шелл-среде. Ибо шелл-сценариями являются все скрипты инициализации системы, многие общесистемные и пользовательские конфигурационные файлы, такие системы управления пакетами, как порты FreeBSD и портежи Gentoo Linux. Ну и то, что любой пользователь свободных ОС рано или поздно начинает писать собственные сценарии оболочки — неизбежно, как распад мировой системы социализма (кто еще не начал — уж поверьте мне на слово, хотя скажи мне такое лет пять назад — сам бы не поверил).
Сказанного, думаю, достаточно, чтобы отнестись к выбору шелла со всей ответственностью. Причем при выборе этом должно учитываться два аспекта применения шелла — как среды для пользовательской работы, так и системы для исполнения общесистемных и пользовательских сценариев.
Первый аспект охватывается понятием интерактивный шелл. Это — любой экземпляр командной оболочки, запущенный пользователем непосредственно. Если этот экземпляр запускается при входе пользователя в систему, его называют login shell. Очевидно, что login shell — также интерактивен, однако в сеансе работы каждого пользователя он будет единственным. Просто же интерактивных шеллов можно запустить сколько угодно — например, в каждом окне эмулятора терминала в Иксах будет функционировать собственная копия интерактивного шелла.
Имя исполняемого файла, запускающего login shell (вместе с полным путем к оному — например, /bin/sh) — атрибут учетной записи каждого реального пользователя системы. Теоретически в этом качестве могут выступать не только собственно шеллы (то есть командные оболочки), но и интерпретатор какого-либо языка программирования (например, Tcl), программа типа Midnight Commander или даже текстовый редактор. Однако эти случаи — специальные, и ниже далее рассматриваться не будут.
Второй аспект использования шелла — неинтерактивный. Неинтерактивный шелл — это экземпляр командной оболочки, вызываемый при выполнении пользователем любой команды или любого сценария. Он может быть вызван неявным или явным образом. Первый случай имеет место быть при выполнении команды из строки оболочки — ведь в этом случае создается (посредством системного вызова fork) точная копия породившего процесса (то есть той же интерактивной оболочки), а уже она вызовом exec запускает на исполнение введенную пользователем команду.
При составлении пользовательского или системного сценария шелл, вызываемый для его исполнения, можно указать явным образом — и настоятельно рекомендуется этой возможностью пользоваться. Делается это в первой строке скрипта, называемой sha-bang, которая по правилам должна иметь вид вроде
#!/bin/bash
То есть после символов решетки (#) и восклицания (! — видимо, для пущей экспрессии:-)) указывать полный абсолютный путь к исполнимому файлу, оболочку запускающему. Делается это, в том числе, и во избежание недоразумений — так, просто единичный символ решетки в первой строке может быть интерпретирован не как комментарий, а как указание на запуск командной оболочки csh. И если сценарий был написан не для нее (а, например, для того же /bin/sh) — он, в силу различия синтаксиса, просто не будет выполнен.
Подчеркнем еще раз: хотя команда, запускающая интерактивный или неинтерактивный шелл, может носить то же имя, что и команда на запуск login shell (а в Linux, скажем, обычно так и есть), это — разные экземпляры программы, которые в общем случае могут быть настроены независимо. А значит — и вести себя разным образом. И потому не следует удивляться, когда bash в эмуляторе терминала не реагирует на управляющие клавиши, привычные для того же bash в виртуальной консоли. А Midnight Commander отказывается в своей командной строке опознавать пути к исполняемым файлам.
Очевидно, что претензии пользователя к интерактивному (особенно к пользовательскому login shell) и неинтерактивному шеллам могут быть разными. В первом случае, как явствует из названия, важнее всего удобство интерактивной работы — развитые средства автодополнения, работы с историей команд, возможности гибкой и информативной настройки приглашения командной строки. Для неинтерактивного же шелла на первый план выходят быстродействие и совместимость.
С быстродействием все понятно — когда единственной задачей командной оболочки является вызов на исполнение другой команды (или, в случае скрипта, серии связанных команд) — тратить ресурсы на обеспечение дополнительных возможностей может быть излишеством. А вот о совместимости следует сказать особо. Но сначала — несколько слов о том,
Какие бывают шеллы
Большая часть командных оболочек делится, на основе синтаксиса интерпретируемого ими языка, на две группы — sh- и csh-совместимые (о специфических шеллах, базирующихся, например, на диалекте LISP, я говорить не буду за их незнанием). На самом деле различия между ними синтаксисом команд не исчерпываются, а лежат глубже — в подходе к обработке командных конструкций, однако сейчас это не существенно.
Оболочки, относимые к sh-совместимым, происходят от первой командной оболочки первых Unix-систем, которую так и называют — shell или Bourne Shell (то есть шелл Борна). В ней были заложены многие возможности для интерпретации команд и их конструкций, то есть составления системных и пользовательских сценариев. Однако по своим интерактивным возможностям она оставляла желать лучшего, и потому на базе ее была создана оболочка Корна (Korne Shell).
Шелл Корна сохранил совместимость с борновским шеллом на уровне синтаксиса, однако привнёс в него как дополнительные возможности интерпретации, так и приемы, направленные на удобство интерактивной работы. И потому именно он лег в основу стандарта POSIX (Portable Operation System Interface), которому должны удовлетворять командные оболочки POSIX-совместимых систем.
Следует заметить, что соответствие этому стандарту — один из критериев отнесения некоей ОС к семейству Unix или Unix-подобных. В частности, именно такой стандартизированный шелл должен вызываться при исполнении общесистемных сценариев (например, инициализации) любой POSIX-системы. Сам же по себе POSIX shell — некая мифическая абстракция, ближе к которой подходит ash (шелл Альмквиста), принятый в качестве стандартной оболочки в NetBSD, а также широко используемый во всяких мини-дистрибутивах Linux и его инсталляционных дисках. Он же, под псевдонимом /bin/sh, представляет умолчальную пользовательскую оболочку из FreeBSD.
Таким образом, ash можно рассматривать в качестве POSIX-шелла par excellence. Интерактивные его возможности проще всего охарактеризовать в сранении с более «продвинутыми» шеллами — и исключительно от противного. А именно: ash не поддерживает автодополнения, не имеет удобных средств доступа к истории команд, и даже средства навигации по командной строке и редактирования оной сводятся к клавише Backspace и ее эквиваленту — Control+H. Встроенных команд также немного (около двух десятков).
Что же остается в сухом остатке? Остается поддержка командных конструкций (перенаправления и конвейеров), возможность фонового выполнения команд, определения псевдонимов и функций. Это позволяет создавать весьма изощренные сценарии, но вряд ли достаточно для комфортной интерактивной работы.
Средства настройки /bin/sh также не блещут разноообразием. Штатно для этой оболочки предусмотрен единственный файл — /etc/profile (и парный ему пользовательский профильный файл — ~/.profile), считываемый при авторизации. Однако, как мы только что выяснили, применять /bin/sh в качестве login shell не очень удобно, а все прочие его экземпляры таким образом оказываются без всяких настроек окружения вообще — что тоже не есть хорошо. И потому для /bin/sh можно установить и второй конфиг, однако этот факт, как и имя такого файла, необходимо определить явным образом в /etc/profile (или в ~/.profile), например, таким образом:
ENV=etc/shrc; export ENV
или, соответственно, так:
ENV=$HOME/.shrc; export ENV
Это увеличивает гибкость настроек /bin/sh, приближая его к более развитым аналогам.
Тем не менее главное названачение условного POSIX-шелла, вне зависимости от того, под какми именем он маскируется — это создание оьщесистемных сценариев. Ибо скрипты, написанные для исполнения в чистом шелле, то есть имеющие sha-bang вида
#!/bin/sh
будут исполняться в любой POSIX-совместимой системе, так как каждая из них обязана содержать исполняемый файл с именем sh — и именно в каталоге /bin. Хотя это будут и не обязательно одни и те же программы, как мы вскоре увидим.
Шеллы и Борна, и Корна не были свободно распространяемыми программами в понимании FSF или BSD. Поэтому ни тот, ни другой не могли использоваться в таких ОС, как *BSD или Linux, хотя свободная реализация оболочки Корна (pdksh) и была создана. Однако, как и ее прототип, шелл Корна, она, несколько развившись относительно первозданного Bourne shell, обладала интерактивными достижениями, далекими от идеала. Столь же слабы они были и в ash. И потому наиболее широкое распространение в мире свободных POSIX-срвместимых операционок получила оболочка bash (что расшифровывается как «еще одна оболочка Борна», «заново рожденный шелл» и тому подобным образом), разработанная в рамках проекта GNU.
Популярность bash в немалой степени была обусловлена его интерактивными возможностями — он аккумулировал все достижения интерактивной мысли sh- и csh-совместимых оболочек, прибавив к ним немало собственных. И умудрившись при этом сохранить базовую совместимость с POSIX shell. Конечно, многие его собственные фичи («bash’измы») выходили за рамки этого стандарта. Однако для соответствия оному был предусмотрен режим совместимости — то есть bash был способен эмулировать стандартный POSIX shell.
Однако главным для bash было то, что эта оболочка оказалась тесно интегрирована с операционной системой Linux: именно bash волею судеб стал одной из первых программ, которые Линус запустил поверх своего новосозданного ядра. И потому идеи bash-скриптинга пронизали Linux до самых его оснований. Ну а для совместимости использовался тот самый режим эмуляции: в Linux файл, запускающий POSIX shell (по стандарту он должен именоваться /bin/sh), являет собой жесткую или символическую ссылку на реальный /bin/bash (или, реже, /usr/bin/bash). Последний же, будучи вызванным таким образом, полностью воспроизводит стандартный POSIX shell (разумеется, путем утраты своих продвинутых фич).
Клан csh-совместимых оболочек развивался параллельно сынам и пасынкам Борна. Собственно оболочка csh была создана в Университете Беркли в ходе реализации проекта BSD Unix (тогда — именно так). Она получила дополнительные интерактивные возможности, во многом превосходящие таковые у современного ей шелла Корна. Главное же — языку, ею интерпретируемому, были приданы черты синтаксического сходства с языком Си (откуда, собственно, и название — C-Shell, хотя не следует думать, что на всамделишний Си ее интерпретируемый язык похож). В результате оболочка csh оказалась весьма эффективной как для интерактивной работы, так и при создании сценариев. Только вот сценарии эти не были совместимы со скриптами POSIX shell, обретшего уже силу стандарта. То есть для создания общесистемных сценариев она оказалась практически не пригодной.
В отличие от большинства прочих достижений берклианской мысли, оболочка csh, по не вполне ясным для меня причинам, не обрела статуса свободной программы. Поэтому она не могла использоваться даже в своих родных пределах — в BSD-системах. Однако на замену ей была изобретена свободная оболочка tcsh — не просто функциональное воспроизводство, но дальнейшее развитие оболочки csh. По интерактивным возможностям она, как минимум, не уступает bash и потому утвердилась в стане свободных BSD-клонов.
В частности, оболочка tcsh принята в качестве login shell для суперпользователя во FreeBSD. Правда, вызывается она в режиме совместимости с csh, однако /bin/csh — не более чем жесткая ссылка на /bin/tcsh,
Оболочка tcsh используется в качестве универсального «умолчального» пользовательского шелла также в OpenBSD. Однако характерно, что все общесистемные сценарии в обеих ОС написаны, тем не менее, в соответствие с требованиями POSIX Shell.
Проблема выбора
Из приведенного краткого обзора можно видеть, что в плане шеллов выбор пользователя достаточно обширен. А ведь я остановился только на самых распространенных. Однако рискну предположить, что большинство начинающих пользователей Linux’а об этом не особо задумывается. Ведь во всех его дистрибутивах в качестве шелла по умолчанию принят bash, обладающий как развитыми средствами интерпретации, так и продвинутыми интерактивными возможностями, обеспечиваемыми его дополнениями из самостоятельного пакета — bash completion. Если к этому приплюсовать относительную простоту настройки, да еще при сохранении совместимости со стандартом, может, казалось бы, возникнуть резонный вопрос: так зачем искать добра от добра?
Первый вариант ответа очевиден — добро это дополнительное ищется в тех случаях, когда необходима минимизация ресурсов. Когда bash, занимающий более полумегабайта на диске (и около полутора — в памяти) оказывается излишне громоздким и медленным. Впрочем, первое играет роль только для всяких rescue-систем на дискетах (и прочих «мелких» носителях), а второе на современных машинах нечувствительно. Тем не менее, маленький и быстрый шелл Альмкивста (ash) может оказаться подходящим не только в спасательных целях, но и для всякого рода скриптинга. Хотя работать в строке ash регулярно мне бы не хотелось…
Вторая причина поиска нового шелла — неудовлетворенность возможностями имеющегося. Эта проблема остро встает перед пользователями FreeBSD — уж очень убог его умолчальный login shell для обычного пользователя в плане интерактивной работы. Что особенно наглядно проступает в сравнении с tcsh,каковой по определению получает в свое распоряжение root-оператор. А потому и простой юзер может поддаться искушению и выбрать себе тот же tcsh — хотя бы ради единства стиля работы (ведь на настольной машине тот же юзер, как правило, сам себе root).
Должен заметить, что именно при первом приобщении к FreeBSD я и перепробовал целый ряд доступных в ней шеллов. Благо через систему портов или коллекцию пакетов они столь же легко удалялись, как и устанавливались. Не обошел я своим вниманием и tcsh — и в целом остался им доволен. Как интерактивная оболочка tcsh, на мой взгляд, несколько превосходит bash (хотя и не принципиально). Однако непривычность синтаксиса (или необходимость его изучения) способны отвратить от этого шелла. Тем паче, что редактирование системных скриптов или, тем более, сочинение собственных сценариев все равно требует обращения к sh-скриптингу. То есть даже виртуозное владение tcsh не освободит от необходимости изучения хотя бы основ последнего.
И, наконец, третья причина для изысканий — поиски идеала (а не они ли движут, осознанно или нет, изрядной долей пользователей свободных POSIX-систем?). Спору нет, bash — оболочка хорошая, но до такого идеала явно не дотягивающая, слишком много в нем направлено на достижение баланса компактности и функциональности. Должен сказать, что мои поиски идеала успехом увенчались. И потому наступает время обратиться к рассмотрению того шелла, который я полагаю лучшим в качестве интерактивного инструмента — Z-Shell, или просто
Я использую zsh с тех самых пор, как осознал его несравненные достоинства, то есть примерно с 2001 года — использую всегда и везде: во всех дистрибутивах Linux’а и BSD-системах. Некоторый перерыв в нашем сотрудничестве пришелся на тот короткий период времени, когда я, идя по стопам всего прогрессивного человечества, перешёл на кодировку UTF8, а мой друг zsh — еще нет. Вынужденно используя bash в Linux (и, для равновесия, tcsh во FreeBSD), я в очередной раз имел возможность сравнить все три оболочки. И сравнение это опять оказалось в пользу zsh’а. Почему, по прошествии стольких лет, я и решил вернуться к его описанию.
Хочу обратить особое внимание — на протяжении всего этого времени, как до перерыва, так и после него, я применял zsh практически с одними и теми же конфигурационными файлами, подвергаемыми лишь косметическим правкам для приведения в соответствие с реалиями конкретной системы, по мере уяснения мною существующих возможностей этой среды или для задействования возможностей новых.
Лишь недавно у меня возникла необходимость в более кардинальной модификации конфигурационных файлов zsh, что составит предмет одной из следующих заметок. А пока —
Представление героя
Итак, zsh (или Z-shell) — оболочка из клана sh-совместимых, первоначально разрабатывавшаяся Паулем Фальстадом (Paul Falstad), начиная с 1990 года. Буква Z в названии этого шелла происходит от логина учётной записи Zhong, принадлежавшей одному из аспирантов Принстонского университета (Zhong Shao), в котором в то время обучался Пауль, и, видимо, появилась тут «для прикола». Однако Z может символизировать и последнее слово в развитии командных оболочек вообще.
Ныне Z-shell развивается в рамках самостоятельного проекта сообществом энтузиастов (Zsh Development Group) при координации Петера Стефенсона (Peter Stephenson), являющегося также автором большей части документации проекта. В отличие от bash, прямого (как, впрочем, и косвенного) отношения к GNU zsh не имеет, и распространяется под собственной лицензией BSD-стиля, а, следовательно, является полностью свободной программой.
Существует мнение (и не только мое), что в zsh нашли свое воплощение все прогрессивные тенденции таких развитых оболочек, как bash и tcsh. И, ознакомившись с его возможностями, с этим трудно не согласиться — в zsh есть все, что было хорошего в тех обеих оболочках, но, если так можно выразиться, в превосходной степени.
Действительно, какими особенностями определяется в первую очередь удобство интерактивной работы в командной оболочке? В порядке, котором с ними сталкивается пользователь, это будут:
- автодополнение командной строки;
- возможности навигации по ней и ее редактирования;
- просмотр буфера истории команд;
- возможность минимизации ввода за счет использования псевдонимов.
Автодополнением клавишей Tab команд, частично введенных в ответ на приглашение оболочки, трудно удивить пользователей bash или tcsh. Столь же естественно, что при возможности безальтернативного дополнения именно оно и происходит, а при наличии некоторых альтернатив выводятся возможные варианты. Однако zsh идет дальше — и после вывода таковых в ответ на последующие нажатия клавиши табулятора начинает автоматический их перебор.
Автодополнение путей к файлам, выступающим в качестве аргументов команд, — тоже не бог весть какое новшество. Автоматический перебор вариантов клавишей табулятора действует и для путей к файлам в аргументах команд. Приятной неожиданностью окажется и то, что автодополнение работает также и для прочих аргументов команд,
Это особенно эффектно просматривается на примере команды man. Так, чтобы вызвать полное экранное руководство по zsh, достаточно набрать
$ man zsha
и нажать табулятор, чтобы развернуть его до полного
$ man zshall
Более того, автодополнению (и автоматическому перебору его возможностей) подвержены даже опции многих команд. Это особенно показательно для таких синтаксически сложных команд, как find. Так, последовательность
$ find / -na
будет автоматически дополнена до
$ find / -name
А после указания этого для указания опции действия можно ограничиться вводом символа дефиса
$ find / -name filename -
и выбрать необходимое действие из предложенного списка, Например, print — вывод на экран, или exec — исполнение сторонней команды.
Некогда, во времена моего освоения zsh, все рассмотренные варианты автодополнений были чистым эксклюзивом этого шелла. Ныне большинство их с помощью соответствующих настроек может быть реализовано и в bash’е — при наличии bash completion, разумеется. Примеры таких настроек можно видеть здесь.
Однако один вариант автодополнения остаётся, насколько мне известно, уникальным для zsh: развертывание путей при сокращенном их наборе. Так, чтобы просмотреть содержимое каталога /home/data/soft/zenwalk/, в командной строке достаточно набрать
$ ls /h/d/s/z
и нажать клавишу табуляции: сокращенный ввод пути (разумеется, при безальтернативности оного) будет автоматически развернут до полного
$ ls /home/data/soft/zenwalk
Автодополнение в 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 lsp='ls -g L'
чтобы при необходимости постраничного вывода списка каталога именно к нему и прибегнуть.
Очень эффективно применение псевдонимов командных конструкций для подавления нежелательного вывода сообщений об ошибках. Всем пользователям команд find и grep известно, что при поиске файлов или текстовых фрагментов за переделами домашненго каталога сплошь и рядом приходится сталкиваться с ситуациями, когда полезный вывод команды тонет в ворохе сообщений типа
find: /var/spool/: Отказано в доступе
Бороться с этим достаточно легко — надо только перенаправить вывод подобных сообщений, например, в бездонную прорву устройства /dev/null, например, так:
$ grep -R 'искомая последовательность символов' * 2> /dev/null
Однако и это достаточно лениво, не говоря уж о том, что постоянно забывается. А вот если раз и навсегда определить псевдоним типа
alias -g N='2>/dev/null'
а потом создать ещё и соответствующий псевдоним для самих команд find и grep, как необходимость напрягать память в каждом случае исчезнет.
Важный момент облегчения существования пользователя в любом шелле — вид приглашения командной строки, должная настройка которого может часто избавить от лишнего набора команд (уж от команды pwd я по возможности стараюсь избавиться именно таким образом). Так вот, zsh поддерживает несколько независимо настраиваемых приглашений — обычное, или первичное (то самое, которое пользователь видет постоянно во время сеанса работы в шелле), вторичное — для многострочных команд, «выделенное», приглашение при выводе вариантов автокоррекции и даже специальное «приглашение» в правой части командной строки. Которое, конечно, собственно приглашением не является, но позволяет вывести полезную информацию, например, текущее время или дату, номер виртуальной консоли или терминального окна, и т.д. Для пущей экспрессии настраивается также передача символов в любом приглашении — цветом ли, выделением, инверсией, подчеркиванием.
Очень полезная возможность — различение вида приглашения для обычного пользователя, получившего права суперпользователя в результате команды
$ su
от собственно административного приглашения, после авторизации «чистым» root’ом — дабы не забывал юзер о временности своих полномочий в первом случае.
Надеюсь, что мне удалось убедить читателя в превосходных интерактивных возможностях оболочки zsh. Теперь стоит поговорить о функциональности, которая проявляется не только в интерактивной работе (но и, скажем, при сочинении скриптов). Функциональность же любой оболочки можно в первом приближении оценить по количеству встроенных в нее команд. То есть — команд, выполняемых внутри самого шелла, без порождения новых процессов, как это происходит при выполнении команд внешних. Очевидно, что такие встроенные команды будут выполняться быстрее и отъедать меньше ресурсов. Это, конечно, не скажется при интерактивной работе на современных машинах, но вот в сложных сценариях — вполне может.
В zsh поддерживается весь набор встроенных команд, стандартизированный для POSIX shell, большинство команд из развитых оболочек bash и tcsh, ну и, разумеется, специфичные для этого шелла команды. Общее число их превышает 80 — примерно столько же, сколько встроено в tcsh и bash вместе взятые.
Очень интересна (и удобна) в zsh работа с командными конструкциями перенаправления. Здесь и множественное перенаправление вывода, когда результат выполнения команды направляется сразу в несколько файлов, и множественное перенаправление ввода — когда команда, напротив, получает аргументы последовательно из более чем одного файла, перенаправление без команды, когда конструкция типа
$ < filename
просто выведет на экран содержимое указанного файла — без привлечения команд типа cat или less.
При перенаправлении возможна группировка команд и использование шаблонов. Так, файлы с именами вида file1 и file2 можно просмотреть одной командой
$ < file{1,2}
Перенаправление ввода/вывода может иногда заменять конвейеризацию команд. Так, конструкция вида
$ sort < file{1,2}
отсортирует содержимое обоих файлов точно так же, как это сделал бы конвейер команд
$ cat file1 file2 | sort
Наконец, еще одна специфическая особенность zsh — т.н. пред-исполнимая модификация команд (precommand modifier), осуществляющаяся перед их интерпретацией. Именно таким образом можно отменить чрезмерно навязчивую автокоррекцию аргументов для одной отдельно взятой команды, например, копирования:
$ nocorrect cp file1 file2
Это запретит попытки коррекции имени вновь создаваемого файла file2 похожим из числа существующих. Причём, занеся в профильный файл псевдоним для команды cp как самой себя с таким премодификатором
alias cp='nocorrect cp'
от нежелательной для определённых команд автокоррекции можно избавиться раз и навсегда.
Легко видеть, что все изобилие возможностей zsh далеко выходит за рамки стандарта POSIX для командных оболочек. Однако, в подтверждение своего соответствия оному, zsh, наступая на горло собственной песне, способен к эмуляции POSIX Shell — для этого достаточно создать файл /bin/sh как символическую ссылку на исполнимый файл zsh, например:
$ ln -s /bin/zsh /bin/sh
После этого при вызове оболочки /bin/sh (интерактивно ли, или в сценарии) на самом деле вызывается zsh — однако ведёт он себя в точности как POSIX shell, то есть утрачивает все свои «продвинутые» возможности.
Возможно и использование zsh в качестве общесистемного шелла — то есть в той роли, которую почти во всех дистрибутивах Linux’а исполняет bash. Впрочем, делать это следует только в случае полной уверенности, что все общесистемные скрипты полностью совместимы с zsh и несут в себе sha-bang
#! /bin/zsh
А такая уверенность может быть только в том случае, если они написаны собственноручно. И. разумеется, при установке zsh надо озаботиться, чтобы его исполняемый файл находился именно в каталоге /bin, а не в /usr/bin или /usr/local/bin, которые могут представлять собой самостоятельные файловые системы.
Некогда я успешно применял zsh в качестве общесистемного шелла в самостройном Linux’е, собранном по мотивам Linux from Scratch Герарда Бикманса. Однако в других дистрибутивах Linux’а от этого лучше воздержаться.
Кроме того, в zsh имеется и некий режим совместимости с командными оболочками клана C-shell. В первую очередь это касается конфигурационных файлов, которым можно придать вид, привычный пользователям csh или tcsh, о чём будет говориться в следующей заметке. Однако в zsh допускается и использование синтаксических конструкций, подобных интерпретируемым языком C-shell. Однако с этим вопросом я детально не разбирался.
Здесь перечислена лишь небольшая часть возможностей оболочки zsh. В частности, я не останавливался на его встроенных функциях, хотя именно они и есть та база, что обеспечивает все описанное (и не описанное) богачество возможностей этого шелла. Не говорил я и о подгружаемых модулях (по типу plug-ins) — а ведь среди последних есть даже собственный ftp-клиент. Ибо для этого потребовалось бы пересказать всю официальную документацию к нему — почти два десятка man-страниц общим объемом (в компрессированном gz-виде) свыше 250 Кбайт, плюс серию руководств с