Язык и интерпретатор языка C-Shell появился в версии системы UNIX Калифорнийского университета в Беркли UNIX BSD4.2 для VAX-11. Основные достоинства этой версии заключаются в добавлении в UNIX редакторов ex и vi, интерпретатора C-Shell, реализации языков ПАСКАЛЬ и ЛИСП, базы данных INGRES и других возможностей.
Стандартным знаком подсказки является процент (%). При желании его можно заменить.
Восклицательный знак ( ! ) выполняет многие специальные функции, в частности ( !! ) означает вызов предыдущей команды.
Знак крышка ( ^ ) используется для разделения строк при коррекции части текста предыдущей команды.
Знак тильда ( ~ ) в качестве префикса имени пользователя расширяет его до полного имени его рабочего каталога.
Фигурные скобки ({ }) группируют список имен файлов в группу имен файлов.
Когда вы входите в C-Shell, он ищет в вашем рабочем каталоге файлы .login и .cshrc. Если такие файлы у вас есть, он выполняет все команды, расположенные в них. Файл .login используется только при входе в C-Shell с терминала; .cshrc - при любом входе.
Встроенный механизм истории интерпретатора C-Shell хранит заданное число последних введенных вами команд. Число хранимых команд равно значению предопределенной переменной history, которую вы можете установить в файле .cshrc командой set:
% set history = 15
(в отличие от Shell при установке переменной требуется слово set).
Чтобы посмотреть хранимые команды, надо распечатать на экране буфер механизма истории командой history, например:
% history 1 ls -l 2 mail 3 history %
Механизм истории обеспечивает возможность вызвать любую из хранимых команд, печатая восклицательный знак и номер команды, например:
% ! 1 ls -l . . . . %
Имеются различные средства для повторного исполнения предыдущих команд, возможно, с изменением части повторяемой команды.
Для коррекции непосредственно предыдущей команды есть следующие средства редактирования.
Пример:
% cd /users/peter/shels /users/peter/shels: No such file or directory.
Допущена ошибка: shels вместо shells. Она исправляется следующим образом:
%^shels^shells^ cd/users/peter/shells %
Исправленная команда заносится в буфер истории:
% history 1 ls -l 2 mail 3 history 4 cd /users/peter/shels 5 cd /users/peter/shells 6 history
Чтобы редактировать произвольную предыдущую команду, можно воспользоваться командой s (substitution) подстановки (см. раздел 8.6).
Исполнение предыдущих команд, сохраненных в буфере истории, без повторного их набора можно осуществить различными способами.
Первый способ: напечатать восклицательный знак и имя команды. Исполняется самая последняя команда из буфера истории с этим именем. Например:
% !cd cd /users/peter/shells.
Необязательно печатать полное имя. Достаточно минимального количества символов начала имени, необходимого для однозначного его опознания в буфере истории, например:
% !c cd /users/peter/shells.
Второй способ: напечатать и номер команды в буфере истории без пробела между ними. Например:
% !1 ls -l <вывод команды ls -l> %
Наконец, имеется возможность использования последнего слова непосредственно предыдущей команды вводом двух знаков !$, например:
% mv /users/wowa/spasewar.c space.c % pr !$ | lpr pr space.c | lpr %
Для исполнения частично измененных предыдущих команд используется средство подстановки :s (substitution) части текста (похожее на аналогичное средство в редакторе ex).
Пусть имеется следующий буфер истории:
% history 1 ls -l 2 mail 3 cd /users/peter/shels 4 cd /users/peter/shells 5 history 6 cd /users/peter/shells 7 ls -l 8 mv /users/wowa/spacewar.c space.c 9 pr space.c | lpr 10 history
Используем средство подстановки для изменения и исполнения команды mv:
% !8 : s /spacewar/empire/ mv /users/wowa/empire.c space.c.
Знак тильда (~) используется в C-Shell для ссылки на собственный рабочий каталог или рабочий каталог другого пользователя, указанного именем пользователя.
Примеры:
% cd progs % mv ~/test.c
Последняя точка означает текущий каталог progs. Чтобы узнать, что же в действительности выполнено, посмотрим буфер истории:
% !h . . . . . . . . . . . . . . 11 mv /users/wowa/empire.c space.c 12 cd progs 12 mv /users/peter/test.c .
Пусть имеется пользователь с именем nick. Чтобы узнать его рабочий каталог, можно использовать команду echo и средство знака тильда:
% echo ~nick /users/nick %
Кроме средств метасимволов для ссылки на множество файлов в C-Shell применяется средство группирования имен файлов для явного указания множества файлов в виде спискф имен файлов, заключенного в фигурные скобки.
Пример:
% cp /users/peter/animals/{cats, dogs, birds}
Или: % cp ~mary/animals/{cats, dogs, birds}.
Эта команда копирует множество из трех файлов с именами:
/users/peter/animals/cats /users/peter/animals/dogs /users/peter/animals/birds
В одной команде можно использовать более одной группы файлов, например:
% echo ls{/bin, /usr/ucb}{pi, is}
ls /bin/pi /bin/is /usr/ucb/pi /usr/ucb/is
Этот механизм, называемый alias, позволяет дать дополнительные (обычно короткие) имена часто используемым (обычно длинным) командам.
Пример:
% alias cdm1 cd /users/sys/doce/mans/man/man1 % alias cdm2 cd /users/sys/doce/mans/man/man2 % alias cdm3 cd /users/sys/doce/mans/man/man3
Чтобы изменить текущий каталог, например, на ...man 2, достаточно ввести соответствующую команду по ее дополнительному имени:
% cdm2 % pwd /users/sys/doce/mans/man/man2.
Те же переименования можно выполнить короче с использованием ссылки !$ на последнее слово команды:
% alias cdm cd /users/sys/docs/mans/man/man \!$ % cdm 3 % pwd / users/sys/docs/mans/man3.
Обратный слэш перед восклицательным знаком исключает действие восклицательного знака как специального символа.
Отмена переименования производится командой unalias, например:
% unalias cdm.
Подобно языку Shell, C-Shell имеет встроенные переменные, установка которых может влиять на поведение интерпретатора. Установка значения переменной производится командой set, имеющей следующий синтаксис:
| set <переменная> = <значение> |
Рассмотрим наиболее употребительные встроенные переменные.
Переменная history задает количество предыдущих команд, сохраняемых в буфере истории, например: set history = 30.
Переменная path устанавливает каталоги для поиска команд. Список каталогов, разделенных пробелами, заключается в скобки:
set path = (/bin /usr/ucb $Home/bin .)
Переменная prompt задает строку подсказки перед выполнением очередной команды. При этом символы \ ! (обратный слэш и восклицательный знак) в строке подсказки задают текущий номер команды, используемый в механизме истории.
Пример:
% set prompt = "ed \ ! >" ed5> history . . . . . . . . 5 history
Переменная Shell указывает, какой интерпретатор вы хотите в качестве начального. Возможные значения: /bin/csh или /bin/sh.
Булевская переменная noclobber используется для защиты уже существующего файла от случайной потери путем перезаписи в него при перенаправлении стандартного вывода. Для этого ее надо установить в значение "истина":
% set noclobber % fgrep ounds /usr/dict/words > shells Shells: File exists -
(файл с именем shells уже существует и его текущая версия была бы потеряна). Если вы тем не менее хотите перезаписать этот файл, используйте перенаправление с восклицательным знаком (>!):
% fgrep ounds /usr/dict/words >! shells
В этом случае перезапись состоится. Установка булевской переменной в противоположное значение "ложь" выполняется командой:
unset noclobber.
Переменные home и cwd, устанавливаемые автоматически, равны полным именам собственного и текущего каталогов соответственно.
Переменная status автоматически возвращает нулевое значение, если текущая команда завершена без ошибок. Ненулевое значение указывает ошибочное завершение.
Переменная argv содержит аргументы командной строки с нумерацией аргументов следующим образом: argv [0] - команда, argv [1] - первый аргумент и так далее (как в языке C).
Доступ к переменным обеспечивается ссылкой на имена с предшествующим знаком $, например, $cwd, $argv [0] и т.д.
Посмотреть текущие значения встроенных переменных можно командой set без параметров:
% set
Пользователь может определить свои переменные типа строка знаков. Например:
% set wd = `pwd` % echo $wd /users/sys/docs.
Здесь результат выполнения команды pwd (строка полного имени рабочего каталога пользователя) присвоен переменной wd, значение которой проверено командой echo.
Кроме строковых переменных можно определить числовые переменные, принимающие значения типа целое, вещественное или булевское. Целое и вещественное значение начинающееся с нуля, считается восьмеричным, иначе - десятичным. Установка значения числовой переменной выполняется командой @ (аналог set для строковых переменных).Пример:
% @ sum = (1 + 4) % echo $sum 5
В общем случае синтаксис команды @ такой:
| @ <переменная> |
где C-операция - один из операторов присваивания, принятых в языке C (=, +=, -=, *=, /=, %=), а C-выражение - выражение в синтаксисе языка C.
Метасимволами называются символы, имеющие специальное значение для интерпретатора.
В C-Shell имеются следующие метасимволы:
Многие из них сходны по функциям с аналогичными функциями метасимволов обычного Shell.
Синтаксические метасимволы:
; - разделяет команды, которые будут выполнены последовательно;
| - разделяет команды, соединенные каналом, так что стандартный вывод левой является стандартным вводом правой;
|& - аналогично |, однако диагностический вывод тоже направляется на ввод следующей команды;
( ) - объединяют команды, разделенные предыдущими знаками, в единое целое для использования в последовательности или с каналом;
& - предписывает выполнение команды на заднем плане параллельно со следующей командой, например:
cat letter>/dev/lp &
|| - аналогичен знаку |, однако правая команда выполняется, только если левая завершилась аварийно;
&& - аналогичен знаку |, однако правая выполняется, только если левая завершилась нормально.
Метасимволы именования файлов:
? - любой символ в имени файла. Например, файлы fa.o, fb.o, fc.o могут быть напечатаны одной командой:
$ cat f?.o > total.o
* - любая строка в имени файла. Например, удаление всех файлов, имена которых начинаются с old:
% rm old*
[] - любая одна буква из указанного в квадратных скобках диапазона. Например:
% ls f.[a - z] - печать всех файлов типа f.x,
где x - буква из диапазона a - z;
{} - аналогичны квадратным скобкам [], однако вместо диапазона указано множество букв. Например, печать файлов list, last, lost:
% ls l{iao}st;
~ - полное имя рабочего каталога пользователя (см.выше);
/ - разделяет имена каталогов и файла в полном имени файла или каталога.
Метасимволы - кавычки:
\ - отменяет мета-значение следующего за ним одного метасимвола. Например:
% ls \* * not found
(в то время как % ls * - печать всех файлов текущего каталога)
' ' - отменяет мета-значения группы символов. Пример:
% set string = 'ws - l $dir / $file'
" " - аналогичны одиночным кавычкам, однако подстановка значений переменных и команд выполняется. Пример:
% echo "$dir is not a directory."
Метасимволы ввода - вывода:
< - перенаправление ввода;
> - перенаправление вывода (если переменная noclobber установлена, перезапись существующего файла вывода не происходит);
>& - перенаправление диагностического вывода;
>! - перенаправление вывода (с обязательной перезаписью существующего файла вывода);
>&! - аналогично >! для диагностического вывода;
>> - аналогично >, однако вывод добавляется в конец существующего файла вывода; если файл не существует и переменная noclobber установлена, возникает ошибка;
>>& - аналогично >&, однако вывод добавляется в конец файла вывода;
>>! - аналогично >>, однако, если файл вывода не существует, он создается (ошибки не возникает);
>>&! - комбинация >>& и >>!
Метасимволы подстановки:
$ - указывает подстановку значения переменной, например:
% set M1 = /usr/man/man3 % cd $M1
! - указывает подстановку команды из буфера истории;
: - указывает подстановку строк в команде из буфера истории;
? - используется в специальных случаях подстановок команд из буфера истории.
Прочие метасимволы:
# (диез) - указывает комментарий C-Shell; начинает имена временных файлов; должен быть первым символом командного файла в C-Shell;
% - указывает номер процесса, например:
kill %1.
В добавление к командам языка Shell в C-Shell появился ряд полезных команд. Рассмотрим некоторые из них.
Команда ls с ключом -F позволяет получить листинг каталога с указанием знаком * исполнимых файлов и знаком / каталогов.
Пример:
% ls -F mail help lint1* tabset/
Команда head, симметричная команде tail, позволяет посмотреть на экране заданное количество первых строк файла (по умолчанию 10 строк), например:
% head -2 people Mary Clark 101 Sally Smith 113
Листание файла на экране позволяет осуществить команда more, например:
% more somefile <первая страница фала> - - More - - (3 %) %
Процент в скобках указывает уже просмотренную часть файла. Для последовательного постраничного просмотра нажмите клавишу пробела, для построчного - клавишу возврата каретки.
Можно задать начало просмотра со строки с заданным номером или заданным значением. Примеры:
% more +194 somefile . . . . . % more +'more then' somefile
В общем случае значение задается регулярным выражением, как в ed или grep (см. раздел 10.5).
Команда apropos позволяет найти разделы руководств, касающиеся заданного ключевого слова.
Пример:
% apropos sort ddsort (3/21/80) - sort DDBS files look (1) - find lines in a sorted list . . . . . . . . . . . . . . . tsort (1) - topological sort % man look <руководство по look (1)>
Просмотреть заголовки руководств можно командой whatis, например:
% whatis mv ln cp cp (1) - copy ln (1) - make links mv (1) - move or rename files
Команда whereis позволяет найти специальные файлы, связанные с указанной командой (опция -m находит файл руководства, опция -b - файл кода команды).
Пример:
% wheris -m rm rm: /usr/man/man1/rm.1 % wheris -b rm rm: /bin/rm
Команда strings позволяет просмотреть в любом (в том числе выполнимом) файле все строки (в коде ASCII).
Выражение, возвращающее значение, зависящее от состояния файла, используется в условных операторах (см.ниже). Значение равно единице (1), если выражение истинно, и ноль (0), если оно ложно или файл не существует.
Синтаксис выражения:
| -op <имя файла>, | где op принимает значения: |
| d - является ли файл каталогом? | |
| e - файл существует? | |
| f - является ли файл простым файлом? | |
| o - это мой собственный файл? | |
| r - имею ли я право чтения файла? | |
| w - имею ли я право записи файла? | |
| x - могу ли я выполнить файл? | |
| z - файл пуст (длина ноль байтов)? |
Пример:
if (-d $dir) then echo "**** $dir is a directory"
Любая последовательность команд, разделенных метасимволами ; или |, а также отдельная команда является работой. Каждая работа выполняется отдельным процессом.
Заканчивая такую последовательность команд или отдельную команду знаком &, можно задать выполнение работы на заднем плане, то есть параллельно с будущими работами. В этом случае система сообщает вам номер работы в скобках и номер процесса, например:
% du > usage & [1] 503 % ls -al <Содержание текущего каталога> %.
По окончании работы система сообщает о завершении (нормальном или аварийном), указывая номер работы и процесса, например:
..... [1] 503 - Done du > usage %.
Чтобы посмотреть, какие работы активны в данный момент, используйте команду jobs -l.
Эта команда распечатает список работ с указанием их состояния:
Running (выполняется) или Stopped (остановлена).
Командный файл (скрипт) - это файл, состоящий из команд, выполняемых группой. Примеры скриптов - файлы .login,.cshrc, .logout. Прежде чем писать свой скрипт, проверьте UNIX Reference используемой Вами версии UNIX, нет ли там команды, уже решающей вашу задачу.
Первый способ выполнения скрипта - ввести команду:
% csh sname arg1 arg2 ...,
где sname - имя скрипта; arg1, arg2 ... - аргументы скрипта.
Аргументы скрипта автоматически помещаются во встроенные переменные $argv[1], $argv[2] и так далее.
Кроме того, аргументы доступны по ссылкам $n, где n - целое, равное позиции аргумента; $0 означает sname. Различие между $argv[n] и $n заключается в том, что первая ссылка дает ошибку при выходе значения n за допустимые пределы, а вторая - нет.
Второй способ выполнения скрипта в C-Shell - обеспечить его выполнимость (командой chmod) и позаботиться о том, чтобы он начинался с символа #(диез); в противном случае скрипт будет выполняться обычным Shell.
Пример:
% chmod a+x sname % sname arg1, arg2, ...
При выполнеии скрипта производится подстановка значений переменных, ссылки на которые указывает знак $. Переменная должна обладать значением в момент ссылки на нее, иначе возникает о шибка.
Узнать, присвоено ли значение переменной, можно с помощью выражения $?<имя> (1 - присвоено, 0 - нет), а количество компонентов значения дает выражение $#<имя>.
На компоненты значения можно ссылаться выражением $<имя>[n], где n - номер компоненты. Компоненты значения разделяются пробелами, а многокомпонентное значение заключается в скобки.
Пример:
% set sum1 = (a b c) % echo $?sum1 1 % echo $#sum1 3 % echo $sum1[2] b % unset sum1 % echo $?sum1 0.
Другими полезными подстановками, начинающимися знаком $, являются:
$* - эквивалентно $argv;
$$ - номер процесса; поскольку он уникален в системе, его удобно использовать для генерации уникального имени временного файла;
$< - заменяется строкой последующего ввода со стандартного ввода (клавиатура терминала), что очень полезно при написании интерактивных скриптов.
Пример:
echo "yes or no?" set a = ($<)
На экране высветится запрос (yes or no?), затем будет прочитан ответ и присвоен переменной a.
Допускается использование выражений над переменными по правилам операций в языке C. Например, операции '==' и '!=' сравнивают строки, операции '&' и '|' реализуют булевские операции 'и' и 'или' и так далее. Введены также специальные операции '=~' и '!~', подобные операциям '==' и '!=', однако в правой строке допускаются метасимволы C-Shell (*, ? и []).
Кроме того, допустимы выражения для оценки состояния файла ( см. раздел 8.13).
Результат выполнения предыдущей команды (нормальное или аварийное завершение) можно получить в виде значения переменной
$status (ноль - без ошибок, не ноль - авария).
Допустимые в C-Shell управляющие структуры взяты из языка C. Напомним, что скрипт в C-Shell должен начинаться с символа #(диез). Этим же символом вводится комментарий, продолжающийся до конца строки.
Оператор цикла foreach имеет синтаксис:
| foreach <индекс> (<список значений индекса через пробелы>) |
| <команда 1> |
| <команда 2> |
| .......... |
| end. |
Все команды выполняются для каждого значения индекса из списка значений.
Внутри цикла можно использовать команду break для прекращения выполнения цикла и команду continue для преждевременного прекращения одной текущей итерации.
При выходе из цикла индекс имеет значение последнего элемента из списка значений.
Условный оператор имеет синтаксис:
| if (<выражение>) then |
| <команда 1> |
| <команда 2> |
| .......... |
| else |
| <команда A> |
| <команда Б> |
| .......... |
| endif |
Если альтернатива else пуста (команды А, Б, ... отсутствуют), else можно опустить. Реализация C-Shell требует, чтобы if и then были обязательно на одной строке.
Допустимы вложенные условные операторы, например:
if (<выражение 1>) then <команда 1> .......... else if <выражение 2> then <команда А> .......... else <команда X> .......... endif endif
Если в первой альтернативе только одна команда, допускается следующий синтаксис:
| if (<выражение>) <команда 1> |
| или: if <выражение>\ |
| <команда> |
где символ \ должен предшествовать символу перевода каретки.
Оператор цикла while имеет синтаксис:
| while (<выражение>) |
| <команда 1> |
| <команда 2> |
| .......... |
| end. |
Внутри цикла допустимы операторы break и continue (см.foreach).
Оператор выбора имеет синтаксис:
| switch (<переменная>) |
| case <значение 1>: |
| <команды> |
| ........ |
| breaksw |
| case <значение 2>: |
| <команды> |
| ........ |
| breaksw |
| ........ |
| case <значение n>: |
| <команды> |
| ........ |
| breaksw |
| default: |
| <команды> |
| ........ |
| breaksw |
| endsw |
В отличие от аналогичного оператора в языке C здесь используется специальный оператор breaksw для выхода из альтернативы.
Выполнение осуществляется следующим образом: значение переменной сравнивается последовательно со значениями 1, 2, ..., n, и выполняются команды первой из альтернатив, для которых значения совпали. Если таких значений не оказалось, выполняются команды из альтернативы по умолчанию (default).
Допускаются метки операторов и оператор goto.
Например:
| loop: |
| <команда 1> |
| <команда 2> |
| .......... |
| goto loop |
Обеспечение ввода в командах скрипта в C-Shell из потока символов текста скрипта вместо стандартного ввода (используемого по умолчанию), потребовало введения специального синтаксиса. Рассмотрим пример скрипта:
# foreach i ($argv) ed -$i << 'STOP' 1, $s/wine/water/g w q 'STOP' end
Строка 'STOP', появляющаяся в тексте скрипта дважды, является меткой, ограничивающей текст ввода, и означает, что стандартный ввод для команды ed заменяется посредством механизма перенаправления (знак <<) вводом текста из файла самого скрипта. Ограничитель 'STOP' заключен в кавычки, чтобы предотвратить подстановку переменных и команды внутри него. В примере редактор ed выполняет глобальную подстановку всех вхождений строки wine на строку water (см. раздел 12.4).
Если ваш скрипт создает временные файлы, вы можете захотеть уничтожить их, даже если прерывание скрипта не позволит вам выполнить скрипт до конца (предполагается, что в конце скрипта временные файлы всегда уничтожаются).
Для этого вам нужно в начале скрипта выполнить команду onintr label, где label - произвольная метка, начиная с которой в вашем скрипте стоят команды, которые будут выполнены, если произойдет прерывание (так как в случае прерывания C-Shell автоматически выполнит команду goto label, где label - метка из команды onintr).
При этом вы можете предусмотреть среди выполняемых в случае прерывания команд в качестве последней команду exit 1, чтобы обеспечить ненулевое значение переменной $status, свидетельствующей о неблагополучном завершении скрипта.
Данный скрипт выполняет сохранение файлов C-программ, которые уже сохранялись ранее. Файлы сохраняются в подкаталоге backup вашего рабочего каталога.
# foreach i ($argv) if ($i \ !~ ~/*.c) then # является ли файл $i файлом С-программы ? echo файл $i не является файлом С-программы continue else echo файл $i является файлом С-программы endif echo check file ~/backup/$i if (-e ~/backup/$i) then # находится ли файл $i в подкаталоге backup? echo файл $i не находится в подкаталоге backup continue endif echo compare two files $i and ~/backup/$i cmp -s $i ~/backup/$i if ($status != 0) then echo новая копия файла $i cp $i ~/backup/$i endif end.
Собственно копирование делается командой cp, а все остальные строчки скрипта организуют цикл и осуществляют проверкия.