*nix-системы всегда были сильны своей командной строкой. Большинство, однако, пользуется исключительно bash, поскольку, как правило, в дистрибутивах его ставят по умолчанию, на иные же переключаться попросту лень. В то же время неплохо бы получить представление об их возможностях, чем мы и займемся в статье.

 

Введение

Во времена MS DOS единственной оболочкой был крайне примитивный (как, впрочем, и весь DOS) COMMAND.COM. Именно из-за своей простоты он начал обрастать двухпанельными файловыми менеджерами, идея которых затем была подхвачена и в POSIX-системах. Многие из тех отечественных пользователей, кто говорит, что работает в командной строке, на самом деле работают в mc — как раз из-за того, что COMMAND.COM когда-то был примитивным. Однако в *nix-системах оболочки были не столь незатейливы, как в DOS. Таким образом, параллельно парадигме двухпанельных файловых менеджеров, привнесенной в *nix фактически извне, развивалась (и развивается) парадигма, «родная» для этих систем, а именно — «чистая» консоль с какой-либо из оболочек, которых существует немало. С учетом их многообразия проблема выбора оболочки в случае, если стандартная (bash) чем-то не устраивает, может стать достаточно острой. В статье будут рассмотрены следующие оболочки:

  • dash — прямой наследник NetBSD-версии ash — оболочки Альмквиста, которая крайне строго соответствует стандартам и за их пределы не выходит, из-за чего никаких иных возможностей в ней не предусмотрено;
  • tcsh — оболочка, входящая в состав FreeBSD-base, имеет синтаксис, близкий к синтаксису C, что, таким образом, делает ее несовместимой с системными скриптами;
  • ksh — оболочка, похожая на оболочку Борна с некоторыми возможностями csh, почти полностью соответствует стандартам POSIX;
  • zsh — оболочка с очень гибкими параметрами, позволяет настраивать буквально все;
  • fish — симпатичная оболочка, «поставил и забыл».

Каждая оболочка будет оценена по десятибалльной шкале по нескольким критериям: это простота использования, функциональность и скорость.

 

dash

Простота использования: 4
Функциональность: 6
Скорость: 10

Де-факто это самая маленькая из оболочек, при запуске в виртуальной памяти она занимает примерно 4 Мбайт (сравни с 31 у bash). Если же говорить о размере исключительно исполняемой части виртуальной памяти, то dash занимает 112 Кбайт (bash — 968 Кбайт). Однако dash до такой степени строго соответствует стандарту POSIX, что напрочь игнорирует все появившиеся с тех пор новшества и некоторые удобные вещи в синтаксисе, а это может привести к проблемам при написании скриптов. В отдельных дистрибутивах в качестве системной оболочки используется bash, поведение которой даже в режиме совместимости с sh не всегда сходится с dash.

Прежде всего необходимо заметить, что dash почти полностью неинтерактивна. Отсутствует автодополнение, история, и даже возможность поменять приглашение командной строки ограничена исключительно статическим текстом. Таким образом, данная оболочка не особо предназначена для применения в качестве пользовательской.

В случае же со скриптами возникает казус. С одной стороны, dash поддерживает только то, что определено в стандарте, который писался довольно давно, следовательно, команд там меньше и синтаксис должен быть проще. С другой же — возникает одно «но» под названием «синтаксический сахар». Этого самого сахара в bash достаточно. Кроме синтаксического сахара (с отсутствием которого в dash еще можно как-то смириться), огромная проблема возникает и с массивами — в описываемой оболочке их нет. Вообще.

Посмотрим теперь, что из синтаксического сахара отсутствует в dash и чем предлагается это заменить. Оператор test, он же [, не поддерживает == (оператор сравнения в стиле С), вместо него нужно использовать просто =. Кроме того, крайне не рекомендуется использовать опции -a и -o. Стоит привести гипотетический пример. Вместо строчки

[ \( "$foo" == "$bar" -a -f /tmp/baz \) -o ! -x /bin/su ]

необходимо использовать строчку

(([ "$foo" = "$bar" ] && [ -f /tmp/baz ]) || [ ! -x /bin/su ])

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

Операции инкремента и декремента в стиле С (++ и --) также не поддерживаются.

Не поддерживаются и такие выражения, как $'', $"", ${}, переменные $LINENO, $RANDOM и некоторые еще, вместо echo рекомендуется использовать printf, let тоже отсутствует.

А что у нас со скоростью работы? Я решил провести синтетический бенчмарк. Было опробовано несколько вариантов, но в итоге остановился на следующем, поскольку в нем используются только встроенные функции оболочки:

$ /usr/bin/time dash -c 'i=0 ; while [ "$i" -lt 10000000 ]; do [ "$1" = "123" ] && echo ok ; i=$(($i+1)) ; done' 

И вот тут dash удивляет. Она выполнила этот цикл за 40 с, в то время как bash — за 2 мин 17 с.

Резюме: dash не предназначена ни для интерактивного использования, ни для написания сложных скриптов. Точнее, писать-то можно, но без синтаксического сахара скрипты будут выглядеть чересчур запутанно. Зато по скорости она более чем в три раза быстрее bash (это, однако, не означает, что разработчик может писать скрипты, как ему заблагорассудится, — скорее уж наоборот). Кроме того, она реально маленькая — для настольных систем это сейчас не особо актуально, конечно, но для встраиваемых может оказаться большим плюсом.

 

tcsh

Простота использования: 8
Функциональность: 7
Скорость: 5

Данная оболочка занимает в памяти чуть меньше места, чем bash, — примерно 29 Мбайт. Именно здесь появилось автодополнение. Посмотрим, что же тут есть такого, чего нет в bash. Во-первых, очень удобная история. Если в bash для автодополнения какой-либо команды на букву w из истории команд нужно было нажать более пяти клавиш, то в tcsh для этого нужно набрать !w и нажать клавишу табуляции. И дальше уже сработает автодополнение. Кроме того, при наборе первых букв команды, сохраненной в истории, можно листать все остальные команды, которые на эти буквы начинаются. Во-вторых, автодополнение тут само по себе работает прекрасно. Оно показывает все варианты дополнения по одному нажатию Tab (а не по двум, как это сделано в bash), и, кроме того, в конце имен каталогов автоматически (после первого нажатия на Tab) ставится слеш — в некоторых версиях bash он ставится только после второго; впрочем, в последней версии Xubuntu поведение идентично. Есть, к сожалению, у автодополнения в tcsh и недостатки. Так, если команда многострочная, помнится только первая строка.

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

Комбинации клавиш по умолчанию Emacs, но можно поставить и vi (bindkey -v), а то и вовсе назначить свои.

Конфигурационный файл называется .tcshrc и может включать в себя иные файлы — для этого применяется команда source. Для совместимости предлагается и файл .cshrc, но на практике им сейчас никто не пользуется. Кроме того, как и у большинства современных оболочек, существует сторонний проект tcshrc, предоставляющий удобный набор конфигов, чтобы не писать их самому. Загрузить его можно с sourceforge.net.

Tcsh с готовым конфигом tcshrc
Tcsh с готовым конфигом tcshrc

Синтаксис скриптового языка несовместим со стандартом POSIX. Так, напрочь отсутствует возможность создавать функции, что очень ограничивает применение оболочки для неинтерактивных действий. Вместо for используется foreach. Также сильно ограничена поддержка однострочников, для их написания требуется использовать printf, что, мягко скажем, не слишком удобно.

Попытаемся измерить скорость данной оболочки, для чего адаптируем к ней бенчмарк:

#!/bin/tcsh

set i = 0

while ($i < 10000000)
    if ($1 == "123") then
        echo ok
    endif
    @ i = $i + 1
end

Результаты крайне огорчают: скрипт выполнялся 7 мин 45 с, что более чем втрое превышает время выполнения аналогичного скрипта в bash.

Резюме: данная оболочка удобна для интерактивного пользования, настраиваема, гибка... но для написания скриптов непригодна в первую очередь из-за того, что практически полностью несовместима с POSIX. Плюс, по-видимому, разработчики здраво рассудили, что скрипты для нее писать никто не будет, следовательно, можно сильно не оптимизировать в плане скорости.

 

ksh

Простота использования: 7
Функциональность: 8
Скорость: 7

Общий объем виртуальной памяти, занимаемой ksh, составил приблизительно 22 Мбайт, из которых целых 1400 Кбайт занимает секция кода (если быть педантичным — секция .text ELF-файла). С точки зрения интерактивного использования данная оболочка отличается от bash тем, что по умолчанию использует режим Vi. Ну а главное отличие, пожалуй, связано с работой с каналами: в bash для выполнения второй команды запускается дочерняя оболочка, а в ksh она исполняется в той же самой оболочке. Например, выполнение следующих команд:

$ echo test | read variable
$ echo $variable

в ksh выведет test, в bash же ничего (в последних версиях bash, впрочем, появилась возможность задать аналогичное поведение с помощью опции lastpipe). Также несколько отличается работа с заданиями. Если в остальных оболочках для перевода задания в фоновый режим после нажатия комбинации используется команда bg 1, то в ksh — bg %1, что может вызвать некоторый дискомфорт у пользователей. Для повтора предыдущей команды применяется команда r. Могут возникнуть и проблемы с привязкой клавиш, хоть оболочка и поддерживает эту функциональность, но, по-видимому, имеются некоторые ограничения; таким образом, в данном отношении ksh проигрывает bash.

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

В быстродействии по показаниям бенчмарка эта оболочка практически сравнялась с dash, а то и превосходит последнюю — в некоторых случаях время выполнения примерно на три секунды меньше.

Пример скрипта ksh, использующего возможности ООП
Пример скрипта ksh, использующего возможности ООП

Резюме: ksh для интерактивного использования, быть может, менее удобна и настраиваема, чем bash (особенно современных версий), но по скриптовому языку и скорости его превосходит.

 

zsh

Простота использования: 9
Функциональность: 9
Скорость: 8

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

Начальная настройка zsh
Начальная настройка zsh

Рассматривать процесс настройки я не буду, отмечу лишь, что во время него сразу обращает на себя внимание обилие опций, относящихся к автодополнению. Посмотрим, как все это работает и насколько эти ожидания оправданны. Чтобы не мучиться с настройками, можно установить набор конфигов oh-my-zsh, для чего следует набрать следующую команду (должен стоять Git, так как он используется при загрузке):

$ sh -c "$(wget https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)"
Первый запуск zsh после настройки
Первый запуск zsh после настройки

Первое, что бросается в глаза при запуске zsh с установленным oh-my-zsh и конфигом по умолчанию, — расцветка приглашения. Расцветка выбрана не от балды — каждый цвет что-то означает. Так, при ненулевом коде возврата стрелочка из зеленой становится красной, а при наличии в текущем каталоге подкаталога .git показывается текущий бранч. Однако расцветка приглашения командной строки — отнюдь не самая важная особенность zsh, поэтому перейдем к автодополнению.

Zsh с oh-my-zsh. Видно, что предыдущая команда вернула ненулевой код возврата
Zsh с oh-my-zsh. Видно, что предыдущая команда вернула ненулевой код возврата
Приглашение zsh в git-репозиторий
Приглашение zsh в git-репозиторий

Автодополнение в zsh сделано на высочайшем уровне. При должной конфигурации (либо установленном oh-my-zsh или любом другом конфиге, которых достаточно на любой вкус) по нажатию на дополняются даже идентификаторы процессов при использовании команды kill. Кроме того, для большинства команд по нажатию на данную клавишу можно просматривать список опций, что в некоторых случаях избавляет от необходимости лезть в man. Есть также коррекция опечаток при автодополнении (не путать с обычной автокоррекцией), позволяющая задавать максимальное количество ошибок, при котором оно произойдет. Более того! Оболочка позволяет использовать сокращения в путях — главное, чтобы путь был уникальный. Например, путь /v/l/dm раскроется (опять же по нажатию клавиши автодополнения) в /var/log/dmesg.

Еще одна полезная возможность — глобальные псевдонимы. Проще всего их рассмотреть на примере. Зададим следующие псевдонимы:

zsh$ alias -g L='| less'
zsh$ alias -g G='| grep'

Теперь наберем команду

zsh$ apt-cache search linux G lowlatency L

При выполнении zsh раскроет эту команду, и без набора лишних букв мы отфильтруем все low latency ядра, выведя их список с помощью less.

Использование глобальных псевдонимов в zsh
Использование глобальных псевдонимов в zsh

Есть также псевдонимы расширений, которые позволяют открыть файл с каким-то расширением, просто набрав его имя в командной строке, — при этом запускается заданная в псевдониме команда. Автокоррекция? И она тоже предлагается — возможности аналогичны tcsh.

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

Бенчмарк выполнился примерно за 1 мин 14 с, что в сочетании с мощностью данной оболочки выглядит очень неплохим результатом.

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

 

fish

Простота использования: 8
Функциональность: 5
Скорость: N/A

Данная оболочка появилась в 2005 году, поэтому она базируется на несколько иных принципах, чем уже описанные оболочки. В частности, для сохранения переменных используется демон fishd, который стартует при запуске первого экземпляра fish данного пользователя. Fish занимает приблизительно 45,5 Мбайт виртуальной памяти, fishd — 26 Мбайт, что в итоге дает общий объем больший, чем у любой другой описанной оболочки.

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

Подсказка при наборе команды в fish
Подсказка при наборе команды в fish

По команде help с помощью xdg-open будет запущен браузер. Попытка выполнить эту команду в текстовом режиме успехом не завершилась — помимо того что она не смогла найти нужный дисплей, сперва не вышло найти links/lynx, а после их установки справка все равно не отобразилась.

Краткое описание команд при автодополнении
Краткое описание команд при автодополнении

Для настройки fish есть два пути. Первый — настроить его вручную с помощью любимого текстового редактора (или скачать аналог oh-my-zsh для fish, который, к слову, и называется почти так же — oh-my-fish). Второй — использовать команду fish_config, которая запустит встроенный веб-сервер и отобразит страницу настройки в браузере. В теории последний вариант выглядит предпочтительным для новых пользователей. На практике же... после запуска этой команды браузер, конечно, открылся — но сделать в нем ничего нельзя было из-за отсутствия jquery.js. Возможно, проблема кроется в дистрибутиве — я использовал fish из репозиториев Ubuntu 15.04 (в CentOS 7 и Debian 8 такой пакет отсутствует).

Веб-интерфейс настройки fish
Веб-интерфейс настройки fish

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

fish$ cat /etc/passwd /etc/shadow > test ^&1

Еще имеется история аргументов. Допустим, если нужно после пинга запустить traceroute на тот же адрес, набираем traceroute и жмем . Оп — и появился введенный ранее адрес.

В смысле написания скриптов данная оболочка не совместима ни с какой другой. Так, для присвоения значений используется синтаксис set var 0 (аналогично var=0), вместо операторов && и || — and и or, вместо обратных кавычек или синтаксиса $() для выполнения результатов команды — обычные скобки, циклы имеют иной синтаксис... Конечно, синтаксис это довольно сильно упрощает, но итогом становится непортируемость скриптов.

Быстродействие оценить я не смог из-за банального отсутствия в fish встроенной арифметики. Есть команда math, но она вызывает bc, что для тестирования не подходит. Я все же попытался, однако скрипт выполнялся крайне медленно и стандартное для данного бенчмарка количество операций не смог выполнить даже за час.

Резюме: оболочка заточена под десктоп-ориентированного новичка. Подсветка команд и аргументов, мини-справка по этим командам, веб-интерфейс встроенной справки и конфигурирования. Однако для применения в чистой консоли и на серверах fish не подходит. Кроме того, несовместимость с остальными оболочками делает ее еще менее пригодной для классической работы.

oh shell

Базовая часть оболочки oh написана на Go. Синтаксис же представляет собой сильно модифицированный Scheme, усовершенствованный с целью поддержки объектов первого класса и хвостовой рекурсии. Как и ранние реализации Scheme, oh рассматривает любую сущность в качестве объекта первого класса, что позволяет построить достаточно мощный заменитель ООП.

Также, поскольку интерпретатор oh написана на Go, он поддерживает параллелизм с помощью каналов, которые опять же являются объектами первого класса. Поскольку oh использует один и тот же синтаксис как для кода, так и для данных, каналы и пайпы зачастую взаимозаменяемы. Oh также поддерживает саморасширяемость — большая часть oh написана на самом oh.

Данную оболочку можно найти на гитхабе.

 

Заключение

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

  • Если необходима оболочка с мощным потенциалом в плане написания скриптов, можно посоветовать ksh — она совместима с sh, но поддерживает в том числе зачатки ООП. Правда, для нормального программирования лучше все же использовать инструменты, для этого предназначенные.
  • Если нужна оболочка с «красивостями» наподобие подсветки команд и веб-интерфейса для настройки, на эту роль более всего подходит fish. Стоит, однако, учесть, что синтаксис ее ни с чем не совместим.
  • Если же необходима скорость скриптов — в этом случае обрати внимание на крайне быструю dash (недаром эту оболочку выбрали в качестве системной в Ubuntu). Одна незадача — dash совершенно не подходит для интерактивного использования.
  • Ну а если хочется просто с удобством работать, то тут имеются два варианта: tcsh и zsh. Первая опять же несовместима в плане написания скриптов с иными и достаточно медленна, но в ней по историческим причинам автодополнение очень развито. Zsh же может эмулировать как csh, так и старые версии ksh, при этом обладая уникальными возможностями автодополнения и настройки строки приглашения.

Выбрать есть из чего, не так ли?

Оставить мнение