Оболочка C ( csh или улучшенная версия, tcsh ) — это оболочка Unix, созданная Биллом Джоем , когда он был аспирантом Калифорнийского университета в Беркли в конце 1970-х годов. Она была широко распространена, начиная с выпуска 2BSD Berkeley Software Distribution (BSD), который Джой впервые распространил в 1978 году. [2] [3] Другими ранними участниками идей или кода были Майкл Юбелл, Эрик Оллман , Майк О'Брайен и Джим Калп. [4]
Оболочка C — это командный процессор , который обычно запускается в текстовом окне, позволяя пользователю вводить и выполнять команды. Оболочка C также может считывать команды из файла, называемого скриптом . Как и все оболочки Unix, она поддерживает подстановку имен файлов , конвейеризацию , встроенные документы , подстановку команд , переменные и управляющие структуры для проверки условий и итерации . Что отличало оболочку C от других, особенно в 1980-х годах, так это ее интерактивные возможности и общий стиль. Ее новые возможности сделали ее использование проще и быстрее. Общий стиль языка больше походил на C и считался более читабельным.
Во многих системах, таких как macOS и Red Hat Linux , csh на самом деле является tcsh , улучшенной версией csh. Часто один из двух файлов является либо жесткой ссылкой , либо символической ссылкой на другой, так что любое имя ссылается на одну и ту же улучшенную версию оболочки C. Исходный код и двоичный файл исходного кода csh являются частью NetBSD .
В Debian и некоторых производных (включая Ubuntu ) есть два разных пакета: csh и tcsh. Первый основан на оригинальной версии BSD csh [5] [6], а последний — это улучшенный tcsh. [7] [8]
tcsh добавил концепции завершения имени файла и команды, а также редактирования командной строки, заимствованные из системы Tenex , которая является источником «t». [9] Поскольку он только добавил функциональность и не изменил то, что уже существовало, tcsh остался обратно совместимым [10] с оригинальной оболочкой C. Хотя он начинался как побочная ветвь от исходного дерева, созданного Джоем, сейчас tcsh является основной ветвью для продолжающейся разработки. tcsh очень стабилен, но новые выпуски продолжают появляться примерно раз в год, состоящие в основном из незначительных исправлений ошибок. [11]
Основными целями разработки оболочки C были ее придание большей схожести с языком программирования C и обеспечение ее лучшего интерактивного использования.
Система Unix была написана почти исключительно на языке C, поэтому первой целью оболочки C был командный язык, который был бы более стилистически согласован с остальной частью системы. Ключевые слова, использование скобок, встроенная грамматика выражений оболочки C и поддержка массивов — все это было сильно под влиянием языка C.
По сегодняшним меркам оболочка C может показаться не особенно похожей на C, чем многие другие популярные языки сценариев. Но в 80-е и 90-е годы разница была поразительной, особенно по сравнению с оболочкой Bourne (также известной как sh ), тогдашней доминирующей оболочкой, написанной Стивеном Борном в Bell Labs . Этот пример иллюстрирует более традиционные операторы выражений и синтаксис оболочки C .
оболочка Борна
#!/bin/sh if [ $ days -gt 365 ] then echo Это больше года . fi
оболочка C
#!/bin/csh if ( $days > 365 ) then echo Это больше года. endif
В Bourne sh отсутствовала грамматика выражений . Условие в квадратных скобках должно было оцениваться более медленными средствами запуска внешней тестовой программы. Команда sh if
принимала свои аргументные слова как новую команду для запуска в качестве дочернего процесса . Если дочерний процесс завершался с нулевым кодом возврата , sh искала then
предложение (отдельный оператор, но часто записываемый объединенным на той же строке точкой с запятой) и запускала этот вложенный блок. В противном случае она запускала else. Жесткое связывание тестовой программы как " test
" и " [
" давало преимущество нотации квадратных скобок и создавало видимость того, что функциональность test была частью языка sh. Использование sh обратного ключевого слова для обозначения конца управляющего блока было стилем, заимствованным из ALGOL 68. [ 12]
Напротив, csh мог напрямую оценить выражение, что делало его быстрее. Он также заявлял о лучшей читаемости: его выражения использовали грамматику и набор операторов, в основном скопированных из C, ни одно из его ключевых слов не было перевернуто, а общий стиль также был больше похож на C.
Вот второй пример, сравнивающий скрипты, вычисляющие первые 10 степеней числа 2.
оболочка Борна
#!/bin/sh i = 2 j = 1 while [ $j -le 10 ] do echo '2 **' $j = $i i = ` expr $i '*' 2 ` j = ` expr $j + 1 ` done
оболочка C
#!/bin/csh установить i = 2 установить j = 1 пока ( $j < = 10 ) echo '2 **' $j = $i @ i * = 2 @j++конец
Опять же из-за отсутствия грамматики выражений скрипт sh использует подстановку команд и команду expr . (Современная оболочка POSIX имеет такую грамматику: оператор может быть записан i=$((i * 2))
или : "$((i *= 2))"
.)
Наконец, вот третий пример, демонстрирующий различные стили оператора switch .
оболочка Борна
#!/bin/sh for i in d * do case $ i in d? ) echo $i короткий ;; * ) echo $i длинный ;; esac done
оболочка C
#!/bin/csh foreach i ( d* ) switch ( $i ) case d?: echo $i - короткие breaksw default : echo $i - длинные endssw end
В скрипте sh « ;;
» обозначает конец каждого случая, поскольку sh в противном случае запрещает пустые операторы.
Вторая цель состояла в том, чтобы оболочка C была лучше для интерактивного использования. Она представила множество новых функций, которые сделали ее более простой, быстрой и удобной для использования путем ввода команд на терминале. Пользователи могли выполнять задачи с гораздо меньшим количеством нажатий клавиш, и она работала быстрее. Наиболее значимыми из этих новых функций были механизмы истории и редактирования, псевдонимы, стеки каталогов, обозначение тильды, cdpath, управление заданиями и хеширование путей. Эти новые функции оказались очень популярными, и многие из них с тех пор были скопированы другими оболочками Unix.
История позволяет пользователям вызывать предыдущие команды и повторно запускать их, набирая всего несколько быстрых нажатий клавиш. Например, ввод двух восклицательных знаков (" !!
") [13] в качестве команды приводит к запуску непосредственно предшествующей команды. Другие короткие комбинации нажатий клавиш, например, " !$
" (что означает "последний аргумент предыдущей команды"), позволяют вставлять части предыдущих команд вместе и редактировать их для формирования новой команды.
Редактирование может быть выполнено не только в тексте предыдущей команды, но и в подстановках переменных. Операторы варьируются от простого поиска/замены строки до анализа имени пути для извлечения определенного сегмента.
Псевдонимы позволяют пользователю ввести имя псевдонима и заставить оболочку C расширить его внутренне в любой набор слов, определенный пользователем. Для многих простых ситуаций псевдонимы работают быстрее и удобнее, чем скрипты.
Стек каталогов позволяет пользователю перемещать или извлекать текущий рабочий каталог , что упрощает переход между различными местами в файловой системе.
Нотация тильды предлагает сокращенный способ указания путей относительно домашнего каталога с использованием символа « ~
».
Клавишу Escape можно использовать интерактивно для отображения возможных вариантов завершения имени файла в конце текущей командной строки.
Cdpath расширяет понятие пути поиска до cd
команды (изменить каталог): если указанный каталог отсутствует в текущем каталоге , csh попытается найти его в каталогах cdpath.
Вплоть до 1980-х годов большинство пользователей имели только простые терминалы с символьным режимом, которые исключали возможность работы с несколькими окнами, поэтому они могли работать только над одной задачей за раз. Управление заданиями оболочки C позволяло пользователю приостанавливать текущую активность и создавать новый экземпляр оболочки C, называемый заданием, набрав ^Z
. Затем пользователь мог переключаться между заданиями с помощью fgкоманды . Активное задание считалось находящимся на переднем плане. Другие задания считались либо приостановленными (остановленными), либо выполняющимися в фоновом режиме .
Хэширование путей ускоряет поиск исполняемых файлов оболочкой C. Вместо того, чтобы выполнять вызов файловой системы в каждом каталоге путей по одному за раз, пока не будет найден файл или не закончатся возможности, оболочка C обращается к внутренней хеш-таблице, созданной путем сканирования каталогов путей. Эта таблица обычно может сообщить оболочке C, где найти файл (если он существует), без необходимости выполнять поиск, и ее можно обновить с помощью rehash
команды.
Оболочка C обрабатывает одну строку за раз. Каждая строка токенизирована в набор слов, разделенных пробелами или другими символами со специальным значением, включая скобки, конвейеризацию и операторы перенаправления ввода/вывода, точки с запятой и амперсанды.
Базовый оператор — это оператор, который просто запускает команду. Первое слово берется как имя команды, которая должна быть запущена, и может быть как внутренней командой, например, , echo
так и внешней командой. Остальные слова передаются в качестве аргументов команды.
На базовом уровне высказываний вот некоторые особенности грамматики:
Оболочка C, как и все оболочки Unix, обрабатывает любой аргумент командной строки, содержащий подстановочные знаки, как шаблон и заменяет его списком всех соответствующих имен файлов (см. подстановку ).
*
соответствует любому количеству символов.?
соответствует любому отдельному символу.[
... ]
соответствует любому из символов внутри квадратных скобок. Диапазоны разрешены, с использованием дефиса.[^
... ]
соответствует любому символу, не входящему в набор.Оболочка C также ввела несколько удобных нотаций (иногда называемых расширенной подстановкой ), которые впоследствии были скопированы другими оболочками Unix.
abc{def,ghi}
является чередованием (также известным как расширение фигурных скобок ) и расширяется до abcdef abcghi .~
означает домашний каталог текущего пользователя.~user
означает домашний каталог пользователя .*/*.c
Поддерживаются несколько подстановочных знаков на уровне каталога, например, « ».
Начиная с версии 6.17.01, также поддерживается рекурсивная подстановка символов в стиле zsh (например, " **/*.c
" или " ") .***/*.html
globstar
Предоставление оболочке ответственности за интерпретацию подстановочных знаков было важным решением в Unix. Это означало, что подстановочные знаки будут работать с каждой командой и всегда одинаково. Однако решение основывалось на способности Unix эффективно передавать длинные списки аргументов через системный вызов exec , который csh использует для выполнения команд. Напротив, в Windows интерпретация подстановочных знаков традиционно выполняется каждым приложением. Это наследие MS-DOS, которая позволяла передавать приложению только 128-байтовую командную строку, что делало подстановку в командной строке DOS непрактичной. Хотя современная Windows может передавать командные строки длиной примерно до 32 тыс. символов Unicode , бремя интерпретации подстановочных знаков остается за приложением.
По умолчанию, когда csh запускает команду, команда наследует дескрипторы файлов stdio csh для stdin , stdout и stderr , которые обычно указывают на окно консоли , в котором запущена оболочка C. Операторы перенаправления ввода-вывода позволяют команде использовать файл вместо ввода или вывода.
>
file означает, что stdout будет записан в file , перезаписывая его, если он существует, и создавая его, если его нет. Ошибки все равно приходят в окно оболочки.>&
file означает, что и stdout, и stderr будут записаны в file , перезаписывая его, если он существует, и создавая его, если его нет.>>
file означает, что stdout будет добавлен в конец file .>>&
file означает, что и stdout, и stderr будут добавлены в конец file .<
file означает, что stdin будет прочитан из file .<<
string — это документ here . Stdin прочитает следующие строки до той, которая соответствует string .Перенаправление stderr самостоятельно невозможно без помощи подоболочки.
set filter = "$home" '/filter'
mkfifo ” $filter " cat " $filter " & ( ( ls /root/ || echo Нет доступа. ) > " $filter " ) >& /dev/null
Системы, поддерживающие файловые дескрипторы как файлы, могут использовать следующий обходной путь.
( ( ( echo ok ; '' ) > /dev/fd/0 ) >& /dev/null < /dev/fd/1 ) | ( echo "$<" пока )
Команды можно объединять в одной строке.
;
означает выполнить первую команду, а затем следующую.&&
означает выполнить первую команду и, если она выполнена успешно с кодом возврата 0 , выполнить следующую.||
означает выполнить первую команду и, если она завершается с ненулевым кодом возврата, выполнить следующую.Команды могут быть соединены с помощью конвейера, который заставляет вывод одной команды подаваться на ввод следующей. Обе команды выполняются одновременно .
|
означает подключить stdout к stdin следующей команды. Ошибки все равно приходят в окно оболочки.|&
означает подключение stdout и stderr к stdin следующей команды.Выполнение одновременно означает «параллельно». В многоядерной (многопроцессорной) системе конвейерные команды могут выполняться буквально одновременно, в противном случае планировщик в операционной системе разбивает время между ними.
При наличии команды, например, " a | b
", оболочка создает канал , затем запускает оба a
и b
со stdio для двух команд, перенаправленных так, чтобы он a
писал свой stdout во вход канала, в то время как b
считывал stdin из выхода канала. Каналы реализованы операционной системой с определенным объемом буферизации, так что a
можно писать некоторое время, прежде чем канал заполнится, но как только канал заполнится, любая новая запись будет заблокирована внутри ОС, пока b
не будет прочитано достаточно, чтобы разблокировать новые записи. Если b
попытается прочитать больше данных, чем доступно, он заблокируется, пока a
не запишет больше данных или пока канал не закроется, например, если a
выходы.
Если слово содержит знак доллара, " $
", следующие символы принимаются как имя переменной, а ссылка заменяется значением этой переменной. Различные операторы редактирования, введенные как суффиксы к ссылке, позволяют редактировать имя пути (например, " :e
" для извлечения только расширения) и другие операции.
Механизмы кавычек позволяют воспринимать специальные символы, такие как пробелы, подстановочные знаки, скобки и знаки доллара, как буквальный текст.
\
означает принять следующий символ как обычный буквенный символ."
string"
— слабая кавычка. Заключенные в нее пробелы и подстановочные знаки воспринимаются как литералы, но подстановки переменных и команд все равно выполняются.'
string'
— сильная кавычка. Вся заключенная в нее строка воспринимается как литерал.Двойные кавычки внутри двойных кавычек должны быть экранированы с помощью "\""
. То же самое относится к символу доллара, чтобы предотвратить расширение переменной "\$"
. Для обратных кавычек, чтобы предотвратить вложенность подстановки команд, требуются одинарные кавычки "'\`'"
.
Подстановка команд позволяет использовать выходные данные одной команды в качестве аргументов другой.
`
команда`
означает взять вывод команды , разбить его на слова и вставить их обратно в командную строку.Ниже приведен пример вложенных подстановок команд.
echo "`echo " \"\` "echo" \"\\\"\\\`\" "echo" \"\\\"\\\\\\\"\\\\\\\`\ \\"\" "эхо " \"\\\"\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\ \\\`\\\\\\\"\\\"\" "эхо" \"\\\"\\\\\\\"\\\\\\\\\\\\\\\ "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\`\\\\\\\\\\\\\\\\\\\\\\ \\\\\\"\\\"\" "pwd" \"\\\"\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ \\\\\\\\\\\`\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\`\\\\\\ \\\\\\\\\"\\\\\\\"\\\\\\\`\\\\\\\"\\\"\\\`\\\"\"\` \" "`"
Обычно, когда оболочка C запускает команду, она ждет завершения команды, прежде чем выдать пользователю еще одно приглашение, сигнализирующее о том, что можно ввести новую команду.
&
означает запуск команды в фоновом режиме и немедленный запрос новой команды.Подоболочка — это отдельная дочерняя копия оболочки, которая наследует текущее состояние, но затем может вносить изменения, например, в текущий каталог, не затрагивая родительскую оболочку.
(
команды )
означают запуск команд в подоболочке.Оболочка C предоставляет структуры управления как для проверки условий, так и для итерации . Структуры управления проверкой условий — это операторы if и switch. Структуры управления итерацией — это операторы while, foreach и repeat.
Существуют две формы оператора if . Краткая форма набирается в одну строку, но может указывать только одну команду, если выражение истинно.
если ( выражение ) команда
Длинная форма использует ключевые слова then, else и endif, что позволяет вкладывать блоки команд внутрь условия.
если ( выражение1 ) тогда команды иначе если ( выражение2 ) тогда команды ...else команды endif
Если ключевые слова else и if находятся в одной строке, csh объединяет их в цепочку, а не вкладывает; блок завершается одним endif.
Оператор switch сравнивает строку со списком шаблонов, которые могут содержать подстановочные знаки. Если ничего не совпадает, выполняется действие по умолчанию, если таковое имеется.
switch ( string ) case pattern1: команды breaksw case pattern2: команды перерывы ... по умолчанию : команды перерывыконцы
Оператор while оценивает выражение. Если оно истинно, оболочка выполняет вложенные команды, а затем повторяет их до тех пор, пока выражение остается истинным.
в то время как ( выражение ) командыконец
Оператор foreach принимает список значений, обычно это список имен файлов, созданный с помощью подстановочных знаков, а затем для каждого из них устанавливает переменную цикла на это значение и запускает вложенные команды.
foreach цикл-переменная ( список-значений ) командыконец
Оператор repeat повторяет одну команду целое число раз.
повторить целочисленную команду
Оболочка C реализует как переменные оболочки, так и переменные окружения . [14] Переменные окружения, созданные с помощью setenv
оператора, всегда являются простыми строками, передаваемыми любым дочерним процессам , которые извлекают эти переменные через envp[]
аргумент main()
.
Переменные оболочки, созданные с помощью операторов set
or @
, являются внутренними для оболочки C. Они не передаются дочерним процессам. Переменные оболочки могут быть как простыми строками, так и массивами строк. Некоторые переменные оболочки предопределены и используются для управления различными внутренними параметрами оболочки C, например, что должно произойти, если подстановочный знак не соответствует ничему.
В текущих версиях csh строки могут иметь произвольную длину, вплоть до миллионов символов.
Переменные можно увеличивать по мере необходимости. Однако, если желательно работать с фиксированным размером, предпочтительнее следующий синтаксис.
# Создает переменную, достаточно большую для хранения 1024 элементов. set fixed = { , }{ , }{ , } { , }{ , } { , }{ , }{ , }{ , }{ , }
Оболочка C реализует грамматику 32-битных целочисленных выражений с операторами, заимствованными из C, но с несколькими дополнительными операторами для сравнения строк и проверки файловой системы, например, проверки существования файла. Операторы должны быть отделены пробелами от своих операндов. Переменные указываются как $
name .
Приоритет операторов также заимствован из C, но с другими правилами ассоциативности операторов для разрешения неоднозначности того, что идет первым в последовательности операторов с одинаковым приоритетом. В C ассоциативность слева направо для большинства операторов; в оболочке C она справа налево. Например,
// C группы слева int i = 10 / 5 * 2 ; printf ( "%d \n " , i ); // печатает 4 i = 7 - 4 + 2 ; printf ( "%d \n " , i ); // печатает 5 i = 2 >> 1 << 4 ; printf ( "%d \n " , i ); // печатает 16
# Группы оболочки C справа
@ i = 10 / 5 * 2 echo $i # печатает 1
@ i = 7 - 4 + 2 echo $i # печатает 1
@ i = ( 2 >> 1 << 4 ) echo $i # печатает 0
Скобки в примере оболочки C нужны для того, чтобы избежать путаницы между операторами сдвига битов и операторами перенаправления ввода-вывода. В любом языке скобки всегда можно использовать для явного указания желаемого порядка оценки, даже если это просто для ясности.
Возвращаемые значения ограничены 8 битами. Для exit
выражений унарный оператор отрицания может использоваться для 32-битной оценки.
выход !! 256 # Возвращает 1.
Хотя сам Стивен Борн признавал, что csh превосходит его оболочку для интерактивного использования, [15] она никогда не была столь популярна для написания скриптов.
В 1983 году и csh, и Bourne shell были доступны для операционной системы UNOS компании Charles River Data Systems среди других инструментов UNIX по лицензии Bell Laboratories . [16]
Первоначально и в течение 1980-х годов нельзя было гарантировать, что csh будет присутствовать на всех Unix и Unix-подобных системах, но sh мог, что делало его лучшим выбором для любых скриптов, которые могли бы запускаться на других машинах. К середине 1990-х годов csh стал широко доступен, но использование csh для скриптов столкнулось с новой критикой со стороны комитета POSIX [17] , который указал, что должна быть только одна предпочтительная оболочка, KornShell , как для интерактивных, так и для скриптовых целей. Оболочка C также подверглась критике со стороны других [18] [19] из-за предполагаемых дефектов синтаксиса оболочки C, отсутствующих функций и плохой реализации.
set
, setenv
и alias
все делали в основном одно и то же, а именно, связывали имя со строкой или набором слов. Но у всех трех были небольшие, но ненужные различия. Знак равенства требовался для a, set
но не для setenv
or alias
; скобки требовались вокруг списка слов для a, set
но не для setenv
or alias
и т. д. Аналогично, if
циклические switch
конструкции , и используют ненужные разные ключевые слова ( endif
, endsw
и end
) для завершения вложенных блоков.Это работало для большинства интерактивно набираемых команд, но для более сложных команд, которые пользователь мог написать в скрипте, это могло легко потерпеть неудачу, выдавая только зашифрованное сообщение об ошибке или нежелательный результат. Например, оболочка C не могла поддерживать конвейеризацию между управляющими структурами. Попытка передать вывод команды foreach
в grep
просто не работала. (Обходной путь, который работает для многих жалоб, связанных с анализатором, заключается в разбиении кода на отдельные скрипты. Если foreach
перенести в отдельный скрипт, конвейеризация работает, поскольку скрипты запускаются путем разветвления новой копии csh, которая наследует правильные дескрипторы stdio. Также возможно разбить коды в одном файле. Ниже приведен пример того, как разбить коды в одном файле.)
Другим примером является нежелательное поведение в следующих фрагментах. Оба они, по-видимому, означают: «Если 'myfile' не существует, создайте его, записав в него 'mytext'». Но версия справа всегда создает пустой файл, поскольку порядок оценки оболочки C заключается в поиске и оценке операторов перенаправления ввода-вывода в каждой командной строке по мере ее чтения, прежде чем проверять остальную часть строки на предмет наличия в ней управляющей структуры.
# Работает как и ожидалось if ( ! -e myfile ) then echo mytext > myfile эндиф
# Всегда создает пустой файл if ( ! -e myfile ) echo mytext > myfile
# Обходной путь (только для tcsh) if ( ! -e myfile ) eval "echo mytext > myfile"
# Второй обходной путь (для csh и tcsh) ( exit ( -e myfile ) && ( ( echo mytext > myfile ) >& /dev/null || echo Невозможно создать файл. ) || echo Файл существует.
Реализацию также критикуют за ее крайне неудачные сообщения об ошибках, например, «0: Событие не найдено», которые не содержат никакой полезной информации о проблеме.
Однако, практикуясь, можно преодолеть эти недостатки (тем самым обучая программиста выбирать более эффективные и безопасные подходы к реализации скрипта).
Ошибка "0: Событие не найдено." означает, что в истории нет сохраненных команд. История может работать некорректно в скриптах, но наличие предустановленных команд в переменной служит обходным путем.
#!/bin/csh -f set cmdlist = ( 'date # 1' \ 'uname # 2' \ 'tty # 3' \ 'id # 4' ) echo -n 'Введите число для выполнения команды из истории: ' set cmdexec = "$<" ( exit ( ! ( "$cmdexec" > 0 && \ "$cmdexec" < = "$#cmdlist" ) ) ) >& /dev/null if ( "$status" ) then echo 'Недопустимый номер события.' foreach cmd ( $cmdlist :q ) echo "$cmd" end exit -1 endif eval "$cmdlist[$cmdexec]"
Предпочитает прерывать коды, рекурсивно выполняя скрипт в качестве обходного пути для функций.
#!/bin/csh -f if ( ! "$?main" ) then if ( ! "$?0" ) then echo 'Вы должны запустить этот скрипт, явно вызвав его файл.' exit -1 endif alias function 'set argv = ( \!* ) ; source "$main"' set main = "$0" set ret = "`function myfunc`" echo "$ret" exit endif перейти к "$1" ; сдвигмояфункция:функция myfunc2echo "Функция А." выходмояфунк2:echo "Другая функция." выход
Оболочка C была чрезвычайно успешной в плане внедрения большого количества инноваций, включая механизм истории, псевдонимы, тильду, интерактивное завершение имени файла, встроенную в оболочку грамматику выражений и многое другое, что с тех пор было скопировано другими оболочками Unix. Но в отличие от sh , которая породила большое количество независимо разработанных клонов, включая ksh и bash , известны только два клона csh. (Поскольку tcsh был основан на коде csh, изначально написанном Биллом Джоем, он не считается клоном.)
В 1986 году Аллен Холуб написал книгу On Command: Writing a Unix-Like Shell for MS-DOS [ 22], в которой описывалась написанная им программа под названием «SH», но которая фактически копировала дизайн и возможности языка csh, а не sh. Сопутствующие дискеты, содержащие полный исходный код для SH и для базового набора утилит Unix (cat, cp, grep и т. д.), можно было приобрести у издателя за 25 и 30 долларов соответственно. Управляющие структуры, грамматика выражений, механизм истории и другие возможности SH Холуба были идентичны таковым в оболочке C.
В 1988 году Hamilton Laboratories начала поставлять Hamilton C shell для OS/2 . [23] Она включала как клон csh, так и набор утилит Unix. В 1992 году Hamilton C shell была выпущена для Windows NT . [24] Версия для Windows продолжает активно поддерживаться, но версия для OS/2 была прекращена в 2003 году. [24] В кратком справочнике начала 1990 года [25] описывалось намерение как «полное соответствие всему языку оболочки C (за исключением управления заданиями)», но с улучшениями в дизайне языка и адаптацией к различиям между Unix и ПК. Самым важным улучшением был нисходящий синтаксический анализатор , который позволял вкладывать или передавать управляющие структуры , что исходная оболочка C не могла поддерживать, учитывая ее специальный синтаксический анализатор. Hamilton также добавил новые возможности языка, включая встроенные и определяемые пользователем процедуры, локальные переменные с блочной структурой и арифметику с плавающей точкой. Адаптация к ПК включала поддержку имен файлов и других соглашений на ПК, а также использование потоков вместо ветвей (которые не были доступны ни в OS/2, ни в Windows) для достижения параллелизма , например, при настройке конвейера.