За всю историю операционной системы UNIX для нее было создано огромное количество различных командных интерпретаторов. Некоторые из них предопределили дальнейшее развитие шеллов, единицы стали стандартом, а многие умерли сразу после рождения. Одни продолжают развиваться и сегодня, другие уже не поддерживаются. Как же сориентироваться и сделать правильный выбор?
Thompson shell
История командных интерпретаторов UNIX началась, как и следовало предполагать, вместе с рождением самой операционной системы. Шелл, вошедший в поставку первой редакции UNIX и написанный Кэном Томпсоном (Ken Thompson), был по сегодняшним меркам очень простым и примитивным. Все, что он мог делать, – это читать команды, введенные пользователем, и запускать их на исполнение. Об интегрированном скриптовом языке, автодополнении и истории команд, так привычных сегодняшнему пользователю UNIX, никто тогда даже и не думал. Хотя возможность перенаправления вывода команды в файл уже была реализована.
В шелл третьей версии UNIX по предложению Дугласа Макилроя (Douglas McIlroy) была добавлена возможность перенаправления вывода одной команды на вход другой, а в четвертой версии она обрела свой нынешний облик (оператор «|»). Также были добавлены операторы if и goto, выполненные как отдельные программы.
Разработчики дистрибутива Programmer’s Workbench UNIX модифицировали шелл Томпсона, чтобы сделать его более пригодным для программирования. В результате они выпустили PWB shell (или Mashey shell, по имени главного разработчика).
Bourne shell
Многочисленные ограничения командного интерпретатора Томпсона не позволяли применять его в качестве полноценного скриптового языка и использовать для автоматизации работы. Этот факт волновал не только самих пользователей, но и программистов, привыкших перекладывать свою работу на плечи «железного помощника». И кто знает, сколько бы продолжалась такая несправедливость, если бы в один прекрасный день Стивен Борн (Stephen Bourne) не сел за терминал и не переписал стандартный шелл UNIX.
Именно перу Стивена Борна принадлежит тот синтаксис скриптового языка, который мы видим чуть ли не ежедневно, работая в консоли или программируя скрипты. И сколько бы пользователи не ругали все эти done, fi, esac и другие синтаксические причуды, Борн позволил UNIX сделать большой шаг вперед и на много лет предопределил направление развития командных интерпретаторов.
Основными нововведениями Борна стали:
- оператор ветвления if … then … elif … else … fi;
- оператор цикла for … do … done;
- оператор выбора case … in … esac;
- переменные окружения;
- подстановка результата исполнения команды (‘$(…)’);
- возможность перенаправления файлового дескриптора 2 (2>), позволяющая разделять поток данных и поток ошибок.
Компания AT&T включила командный интерпретатор Борна в базовую поставку седьмой версии UNIX, полностью заменив им шелл Томпсона. Позднее Кэннет Алквист (Kenneth Almquist) создал свободный вариант шелла Борна под названием Almquist shell (ash). Сегодня он используется в Debian, Ubintu и некоторых BSD-системах как интерпретатор стартовых скриптов, а также входит в состав пакета BusyBox, предназначенного для использования во встроенных версиях Linux.
C shell
Можно было бы предположить, что после того как Стивен Борн расширил шелл Томпсона до полноценного скриптового языка программирования, история командных интерпретаторов пойдет эволюционным путем и завершится где-нибудь на отметке zsh. Но все повернулось совершенно иначе. В 1979 году небезызвестный Билл Джой (Bill Joy), активный разработчик BSD UNIX и создатель редактора vi, сделал свою версию командного интерпретатора со встроенным скриптовым языком и назвал его C shell (csh).
C shell не унаследовал нововведений, сделанных Стивеном Борном, потому как базировался на коде командного интерпретатора шестой версии UNIX, который был хоть и расширенным, но все же шеллом Томпсона. Скриптовый язык csh не уступает шеллу Борна по мощности, но отличается синтаксисом. В то время как Борн скопировал все основные операторы с языка Algol68, Билл Джой использовал в качестве макета язык Си, вероятно, руководствуясь своими предпочтениями и предпочтениями других пользователей BSD UNIX.
Некоторым пользователям синтаксис C shell может показаться более правильным и очевидным, нежели синтаксис шелла Борна, но на самом деле это не так. В начале 90-х C shell подвергся большой критике за свою двусмысленность и немногословность интерпретатора, останавливающего выполнение скрипта, но не сообщающего никаких подробностей о том, что же все-таки произошло. Порой скрипты csh работали совсем не так, как этого ожидал пользователь. Также встречались ситуации, когда интерпретатор отбраковывал, казалось бы, непротиворечивые строки кода.
Но все-таки Биллу Джою нужно отдать должное. В csh было сделано несколько нововведений, которые не только стали частью всех современных командных интерпретаторов UNIX, но и вошли в стандарт POSIX. Среди них:
- расширение пути до домашнего каталога (символ «~»);
- псевдонимы (команда alias);
- управление заданиями (фоновое исполнение команды с помощью указания символа «&» после команды и встроенная команда jobs);
- работа с историей (повторное выполнение команды с помощью указания перед ней символа «!» и навигация по истории команд);
- массивы;
- математические операции.
C shell вошел в поставку 4.1BSD и до сих пор остается базовой частью всех ее потомков, в том числе FreeBSD и OpenBSD.
TENEX C shell
Кэн Грир (Ken Greer), вдохновленный возможностями командного интерпретатора операционной системы TENEX, создал свою, расширенную версию C shell и назвал ее TENEX C shell (tcsh). Основной инновацией шелла стала одна из самых востребованных сегодня возможностей – автодополнение путей и команд. Именно эта особенность сделала шелл TENEX таким привлекательным и, как следствие, стала главной причиной его популярности. Несколько позднее в tcsh была добавлена другая не менее интересная и востребованная возможность – редактирование командной строки. Теперь можно было стереть введенную строку, заменить в ней слова, переместить курсор в начало или конец строки (большинство современных командных интерпретаторов используют библиотеку readline для выполнения таких манипуляций).
По мере развития tcsh в него добавлялось все больше новых функций. Сегодняшняя версия этого шелла обладает такими возможностями, как:
- редактирование командной строки с поддержкой стилей vi и emacs;
- программируемое автодополнение (шелл можно настроить так, чтобы по нажатию <Tab> дополнялись не только имена команд и пути, но и, например, поддерживаемые командой флаги);
- проверка правописания имен файлов, команд и переменных;
- расширенный механизм навигации по каталогам (команды pushd, popd, dirs);
- периодические события (например, отложенное во времени исполнение команды или «сброс» пользователя по истечении тайм-аута).
- возможность указания в приглашении различной полезной информации (текущий каталог, время, дата).
Это лишь некоторые из функций tcsh. По всем признакам это современный и удобный в использовании командный интерпретатор, развитие которого продолжается по сей день.
Korn shell
На tcsh история командных интерпретаторов с Си-подобным синтаксисом фактически заканчивается, и мы возвращаемся к потомкам шелла Борна. В начале 80-х Дэвид Корн (David Korn), один из сотрудников Bell Labs, начал работу над командным интерпретатором, расширяющим возможности шелла Борна. По сложившейся традиции, новый шелл был назван в честь создателя – Korn shell (ksh).
В первую версию ksh вошло несколько изменений, облегчающих создание скриптов, а также скопированные из csh (по просьбам пользователей) функции работы с историей. В шелле Корна впервые появилась возможность редактирования командной строки (стили emacs и vi), позже она была перенесена в tcsh. Кроме того, шелл Корна позволял использовать клавиши «вверх» и «вниз» для навигации по истории. Версия, выпущенная в 1986 году, обрела полную совместимость с мультибайтовыми кодировками.
Версия ksh88 стала частью UNIX System V Release 4 и была одобрена для включения в стандарт POSIX. В последнем релизе ksh, выпущенном в 1993 году, появилась возможность изменения функций горячих клавиш, а также множество дополнений к скриптовому языку. В частности, интерпретатор ksh93 научился работать с ассоциативными массивами (хэш, в терминологии Perl), выполнять операции над числами с плавающей точкой, динамически загружать встроенные команды, работать с «активными» и «смешанными» переменными (это придавало переменным некоторые черты «объектов»). Также в эту версию ksh была добавлена полностью совместимая со стандартом ANSI-C функция printf.
Оригинальная версия ksh до 2000 года оставалась закрытой, и поэтому появилось несколько совместимых командных интерпретаторов, распространяемых свободно. В их число вошли pdksh (Public Domain Korn shell), bash и zsh.
Bourne again shell
Bourne again shell (bash) – это командный интерпретатор, созданный Браином Фоксом (Brian Fox) в рамках проекта GNU. Вначале он позиционировался как свободная замена закрытому ksh, но позднее вырос в независимый продукт с несколькими оригинальными нововведениями. Bash полностью совместим с шеллом Борна и стандартом POSIX. Многие его возможности взяты из ksh и csh. Редактирование командной строки, история команд, фоновое исполнение заданий, стек каталогов (команды pushd и popd), подстановка результата исполнения команды (‘$(…)’), автодополнение имен команд и каталогов, встроенная поддержка арифметических операций (‘((…))’) – все это есть в bash.
Кроме того, bash обладает несколькими уникальными характеристиками, такими как, например, одновременное перенаправление выходного потока и потока ошибок (&>), перенаправление стандартного входа из строки (<<< ‘строка’), открытие и закрытие файлов (exec 3 <file; exec 3 <&-) и работа с сокетами (exec 3<>/dev/tcp/www.host.ru/25; echo -e “HELLO www.myhost.ru” >&3). В третью версию bash были добавлены встроенный отладчик скриптов, возможность сравнения с регулярным выражением ([[ строка =~ шаблон ]]) и новый вид замен (конструкция «{x..y}» заменяется строкой из чисел от x до y).
Bash – наиболее популярный командный интерпретатор на сегодняшний день. Он включен в стандартную поставку абсолютного большинства дистрибутивов Linux, а во многих из них выступает в качестве интерпретатора стартовых скриптов.
Z shell
«Перенесите большой и тяжелый кухонный комбайн, способный заменить всю остальную бытовую технику на Вашей кухне, в мир командных интерпретаторов – и Вы получите Z shell» – с таких слов должна начинаться web-страница программы zsh.
Z shell (zsh) был написан в 1990 году Полом Фолстадом (Paul Falstad) во время его учебы в университете Принстона. Имя для командного интерпретатора он выбрал практически случайно, использовав логин zsh, которым пользовался ассистент его учителя Zhong Shao для входа в операционную систему.
Описать zsh, даже поверхностно, в таком маленьком обзоре практически невозможно. Zsh – это огромный «комбайн», которым можно заменить все остальные шеллы, представленные в этой статье. Он может быть подобен sh, csh или tcsh. Он может быть полностью совместим с bash, а может быть не похож ни на что. Можно применять zsh как ftp- или irc-клиент, писать с его помощью серверные программы, обрабатывающие запросы клиентов, или вовсе не знать о его мощи и использовать как обычный командный интерпретатор. По заложенному в программу потенциалу и многогранности областей применения zsh сравним разве что с редактором emacs.
Кроме эмуляции функциональности всех рассмотренных выше командных интерпретаторов, zsh также порадует пользователя следующими возможностями:
- очень гибкий механизм программируемых автодополнений (в теории, zsh можно научить дополнять по клавише <Tab> все что угодно);
- расширенные маски файлов (‘*’ и ‘?’ – это лишь начальный уровень, по меркам zsh);
- расширенные функции работы с переменными и массивами;
- расширенный механизм редактирования командной строки (zsh использует собственный вариант readline, названный zle, который делает редактирование строк более гибким);
- расширенный механизм настройки приглашения (zsh позволяет, например, поместить часть приглашения в правую сторону экрана);
- единая история команд для всех запущенных экземпляров zsh (можно быть уверенным, что история одного экземпляра zsh не перекроет историю другого);
- загружаемые модули, позволяющие расширять набор встроенных команд без модификации кода (например, модуль zftp для работы с протоколом ftp добавляет в набор одноименную команду);
- zsh чрезвычайно конфигурируемый, практически любой его параметр поддается настройке.
Практически неограниченная мощь zsh одновременно является и его недостатком. Это очень трудный в освоении командный интерпретатор (имеется в виду освоение всех функций), полное описание которого занимает больше 300 страниц формата A4.
Friendly interactive shell
Описанные выше шеллы в большинстве своем достаточно сложны для освоения новичками и не могут быть отнесены к разряду дружелюбных к пользователю программ. Fish, созданный Axel Liljencrantz (не возьмусь за перевод этого имени), выгодно отличается от них в этом отношении. Этот командный интерпретатор не просто наиболее близок к определению «простой в использовании шелл», но и представляет несколько функций, интересных даже профессионалам.
Хотя синтаксис скриптового языка fish несколько отличается от синтаксиса bash и других шеллов, этот факт нас мало волнует. Наиболее «вкусные» его особенности связаны с интерактивным аспектом работы программы. В fish встроен расширенный механизм автодополнений, который печатает не только возможные варианты дополнений, но и их описание (набрав, например, «l», ты получишь на экране таблицу, в которой будут перечислены все команды, начинающиеся с «l», и краткое описание каждой из них). При возникновении ошибки fish выводит не только полное описание ошибки, но и возможные пути ее решения. Кроме этого, fish подсвечивает синтаксис своего скриптового языка прямо в окне терминала.
Хронология развития командных интерпретаторов UNIX
- Thompson shell (1971 год, первая версия UNIX, Ken Thompson);
- Bourne shell, или sh (1977 год, Version 7 UNIX, Stephen Bourne);
- C shell, или csh (1979 год, 4.1BSD, Bill Joy);
- Tenex C shell, или tcsh (конец 70-х, BSD UNIX, Ken Greer);
- Korn shell, или ksh (1983 год, AT&T UNIX, David Korn);
- Bourne again shell, или bash (1987 год, POSIX, Brian Fox);
- Z shell, или zsh (1990 год, POSIX, Paul Falstad);
- Friendly interactive shell, или fish (2005 год, POSIX, Axel Liljencrantz).
Особенности оболочки ash
Оболочка ash представляет собой одну из самых маленьких оболочек, доступных в *nix (за счет малых требований к памяти и дисковому пространству, по сравнению с другими sh-совместимыми оболочками). Этот командный интерпретатор имеет 24 встроенные команды и 10 различных опций командной строки. Обычно ash используется при загрузке Linux в однопользовательском режиме, в защищенном режиме или при загрузке дискетных версий Linux. Также с ее помощью можно проверять скрипты на sh-совместимость. В NetBSD в качестве /bin/sh работает именно ash.
INFO
Shell (наиболее близкий аналог в русском языке – оболочка) – программное обеспечение, создающее интерфейс между пользователем и операционной системой. Shell может быть как текстовым (CLI, командный интерпретатор), так и графическим (GUI). К первому типу можно отнести командные интерпретаторы sh, bash, zsh, второй составляют комплексы программ, обеспечивающих графическое окружение пользователя, такие как KDE, Gnome и XFCE.
Для пользователя современных UNIX-подобных операционных систем установка, удаление или замена командного интерпретатора – обычное дело. Но так было не всегда. Шелл, исполняемый как отдельный процесс, впервые появился в ОС Multics, предшественнице UNIX. В более ранних операционных системах он был встроен в ядро.
Автор: Евгений «j1m» Зобнин
Опубликовано в апрельском номере журнала Хакер