Интерпретатор командного языка shell
1. Основные понятия языка shell 1.1. Ввод-выводТри направления ввода-вывода являются выделенными - стандартный ввод, стандартный вывод и стандартный протокол. Как правило, команды берут исходные данные из стандартного ввода и помещают результаты в стандартный вывод.
Стандартные ввод, вывод и протокол можно переназначить. Обозначение
< <имя файла>служит для переназначения стандартного ввода (дескриптор файла 0),
> <имя файла>для стандартного вывода (дескриптор файла 1);
<< <строка>ввод происходит со стандартного ввода, пока не встретится указанная <строка> или конец файла,
>> <имя файла>для стандартного вывода; если файл существует, то выводимая информация добавляется к конец этого файла,
<& <цифра>в качестве стандартного ввода об(r)является файл, ассоциированный с дескриптором <цифра>; аналогично для стандартного вывода
>& <цифра> <&- и >&-закрывают соответственно стандартный ввод и вывод.
Если любой из этих конструкций предшествует цифра, то с указанным файлом будет ассоциирован дескриптор, равный указанной цифре, вместо 0 и 1 по умолчанию. Например,
2 > <имя файла>для стандартного протокола используется дескриптор 2, а
2 >& 1ассоциирует дескриптор 2 с файлом, ассоциированным с дескриптором 1.
... 2>protocolпереназначает стандартный протокол (дескриптор 2) в файл по имени protocol.
Чтобы переназначить стандартный протокол туда же, куда уже назначен стандартный вывод, следует употребить конструкцию
... 2>&1Важен порядок переназначения: shell производит переназначение слева направо по указанному списку. Так,
1 > xxx 2 >& 1сначала ассоциирует дескриптор 1 с файлом xxx, а затем дескриптор 2 с 1, т.е. тоже с xxx. А
2 >& 1 1 > xxxассоциирует дескриптор 2 с терминалом, а 1 - с файлом xxx.
Можно переназначить системный ввод на текущий файл:
isql - - < 1.2. Синхронное и асинхронное выполнение командОбычно shell ждет завершения выполнения команды. Однако имеется возможность запустить задачу в асинхронном режиме, т.е. без ожидания ее завершения. Для этого после команды (после всех ее аргументов и указаний о переназначении ввода-вывода) надо поставить знак &. При этом по умолчанию стандартный ввод команды назначается на пустой файл /dev/null.
Пример: создать файл primer можно по команде
echo > primerЕще пример: запустить программу prog в асинхронном режиме, чтобы не надо было дожидаться его завершения, засечь время выполнения, результаты программы направить в файл prog.res, данные о времени выполнения - в файл prog.tim.
time prog > prog.res 2> prog.tim & 1.3. КонвейерКонвейер - последовательность команд, разделенных знаком |. Если после конвейера стоит ; shell ждет его завершения. Если & - то не ждет. Роль ; может играть конец строки. Смысл конвейера в том, что стандартный вывод одной команды замыкается на стандартный ввод другой. Пример конвейера - подсчитать число об(r)ектных файлов в текущем каталоге.
ls *.o | wc -l 1.4. Метасимволы, генерация имен файловМетасимволы - символы, имеющие специальное значение для интерпретатора :
? * ; & ( ) | ^ < > <пробел> <табуляция> <возврат_каретки>Однако каждый из этих символов может представлять самого себя, если перед ним стоит . Все символы, заключенные между кавычками ' и ', представляют самих себя. Между двойными кавычками (") выполняются подстановки команд (см п. 2.2) и параметров (см. п. 2.3), а символы , `," и $ могут экранироваться предшествующим символом .
После всех подстановок в каждом слове команды ищутся символы *,?, и [. Если находится хотя бы один из них, то это слово рассматривается как шаблон имен файлов и заменяется именами файлов, удовлетворяющих данному шаблону (в алфавитном порядке). Если ни одно имя файла не удовлетворяет шаблону, то он остается неизменным. Значения указанных символов:
* | любая строка, включая и пустую |
? | один любой символ |
[...] | любой из указанных между ними символов. Пара символов, разделенных знаком -, означает любой символ, который находится между ними, включая и их самих. Если первым символом после "[" идет "!", то указанные символы не должны входить в имя файла |
Строки, начинающиеся с #, трактуются как комментарии.
2.2. Подстановка результатов выполнения командВыражения можно заключать в обратные кавычки (`). Такие выражения вычисляются в месте использования. Они могут быть, например, частью строк. Пример. Пусть параметром макрокоманды является имя файла с расширением .for. Требуется удалить одноименный файл с расширением .err.
name=`ena -n $1` rm -f ${name}.errЗначение, полученное в результате выполнения команды
ena -n $1присваивается переменной name. Фигурные скобки использованы для выделения аргумента операции перехода от имени к значению. Без них .err приклеилась бы к имени.
2.3. Переменные и подстановка их значенийВсе переменные в языке shell - текстовые. Их имена должны начинаться с буквы и состоять из латинских букв, цифр и знака подчеркивания (_). Чтобы воспользоваться значением переменной, надо перед ней поставить символ $. Использование значения переменной называется подстановкой.
Различается два класса переменных: позиционные и с именем. Позиционные переменные - это аргументы командных файлов, их именами служат цифры: $0 - имя команды, $1 - первый аргумент и т.д. Значения позиционным переменным могут быть присвоены и командой set (см. Специальные команды). Пример. После вызова программы на shellе, хранящейся в файле ficofl:
ficofl -d / *.forзначением $0 будет ficofl, $1 - -d, $2 - /, $3 - *.for, значения остальных позиционных переменных будут пустыми строками. Заметим, что если бы символ * при вызове ficofl не был экранирован, в качестве аргументов передались бы имена всех фортранных файлов текущей директории.
Еще две переменные хранят командную строку за исключением имени команды: $@ эквивалентно $1 $2 ..., а $* - "$1 $2 ...". Начальные значения переменным с именем могут быть установлены следующим образом:
<имя>=<значение> [ <имя>=<значение> ] ...Не может быть одновременно функции (см. Управляющие конструкции) и переменной с одинаковыми именами. Для подстановки значений переменных возможны также следующие конструкции:
${<переменная>}если значение <переменной> определено, то оно подставляется. Скобки применяются лишь если за <переменной> следует символ, который без скобок приклеится к имени.
${<переменная>:-<слово>}если <переменная> определена и не является пустой строкой, то подставляется ее значение; иначе подставляется <слово>.
${<переменная>:=<слово>}если <переменная> не определена или является пустой строкой, ей присваивается значение <слово>; после этого подставляется ее значение.
${<переменная>:?<слово>}если <переменная> определена и не является пустой строкой, то подставляется ее значение; иначе на стандартный вывод выводится <слово> и выполнение shellа завершается. Если <слово> опущено, то выдается сообщение "parameter null or not set".
${<переменная>:+<слово>}если <переменная> определена и не является пустой строкой, то подставляется <слово>; иначе подставляется пустая строка.
Пример: если переменная d не определена или является пустой строкой, то выполняется команда pwd
echo ${d:-`pwd`}Следующие переменные автоматически устанавливаются shell'ом:
# | количество позиционных параметров (десятичное) |
- | флаги, указанные при запуске shellа или командой set |
? | десятичное значение, возвращенное предыдущей синхронно выполненной командой |
$ | номер текущего процесса |
! | номер последнего асинхронного процесса |
@ | эквивалентно $1 $2 $3 ... |
* | эквивалентно "$1 $2 $3 ..." |
Напомним: чтобы получить значения этих переменных, перед ними нужно поставить знак $. Пример: выдать номер текущего процесса:
echo $$ 2.4. Специальные переменныеShell'ом используются следующие специальные переменные:
HOME | директория, в которую пользователь попадает при входе в систему или при выполнении команды cd без аргументов |
PATH | список полных имен каталогов, в которых ищется файл при указании его неполного имени. |
PS1 | основная строка приглашения (по умолчанию $) |
PS2 |
дополнительная строка приглашения (по умолчанию >); в интерактивном режиме перед вводом команды
shell'ом выводится основная строка приглашения. Если нажата клавиша new_line, но для завершения команды требуется дальнейший ввод, то выводится дополнительная строка приглашения |
IFS | последовательность символов, являющихся разделителями в командной строке (по умолчанию это <пробел>, <табуляция> и <возврат_каретки>) |
Простая команда - это последовательность слов, разделенная пробелами. Первое слово является именем команды, которая будет выполняться, а остальные будут переданы ей как аргументы. Имя команды передается ей как аргумент номер 0 (т.е. имя команды является значением $0). Значение, возвращаемое простой командой - это ее статус завершения, если она завершилась нормально, или (восьмеричное) 200+статус, если она завершилась аварийно.
Список - это последовательность одного или нескольких конвейеров, разделенных символами ;, &, && или || и быть может заканчивающаяся символом ; или &. Из четырех указанных операций ; и & имеют равные приоритеты, меньшие, чем у && и ||. Приоритеты последних также равны между собой. Символ ; означает, что конвейеры будут выполняться последовательно, а & - параллельно. Операция && (||) означает, что список, следующий за ней будет выполняться лишь в том случае, если код завершения предыдущего конвейера нулевой (ненулевой).
Команда - это либо простая команда, либо одна из управляющих конструкций. Кодом завершения команды является код завершения ее последней простой команды.
3.1. Цикл ДЛЯ for <переменная> [ in <набор> ] do <список> doneЕсли часть in <набор> опущена, то это означает in "$@" ( то есть in $1 $2 ... $n). Пример. Вывести на экран все фортранные файлы текущей библиотеки:
for f in *.for do cat $f done 3.2. Оператор выбора case $<переменная> in <шаблон> | <шаблон>... ) <список> ;; . . . esacОператор выбора выполняет <список>, соответствующий первому <шаблону>, которому удовлетворяет <переменная>. Форма шаблона та же, что и используемая для генерации имен файлов. Часть | шаблон... может отсутствовать.
Пример. Определить флаги и откомпилировать все указанные файлы.
# инициализировать флагflag=# повторять для каждого аргументаfor ado case $a in # об(r)единить флаги, разделив их пробелами -[ocSO]) flag=$flag' ' $a ;; -*) echo 'unknown flag $a' ;; # компилировать каждый исходный файл и сбросить флаги *.c) cc $flag $a; flag= ;; *.s) as $flag $a; flag= ;; *.f) f77 $flag $a; flag= ;; # неверный аргумент *) echo 'unexpected argument $a' ;; esacdone 3.3. Условный оператор. if <список1> then <список2> [ elif <список3> then <список4> ] . . . [ else <список5> ] fiВыполняется <список1> и, если код его завершения 0, то выполняется <список2>, иначе - <список3> и, если и его код завершения 0, то выполняется <список4>. Если же это не так, то выполняется <список5>. Части elif и else могут отсутствовать.
3.4. Цикл ПОКА while <список1> do <список2> doneДо тех пор, пока код завершения последней команды <списка1> есть 0, выполняются команды <списка2>. При замене служебного слова while на until условие выхода из цикла меняется на противоположное.
В качестве одной из команд <списка1> может быть команда true (false). По этой команде не выполняется никаких действий, а код завершения устанавливается 0 (-1). Эти команды применяются для организации бесконечных циклов. Выход из такого цикла можно осуществить лишь по команде break (см. Специальные команды).
3.5. Функции <имя> () { <список>; }Определяется функция с именем <имя>. Тело функции - <список>, заключенный между { и }.
3.6. Зарезервированные словаСледующие слова являются зарезервированными:
if then else elif fi case in esac { } for while until do done 3.7. Специальные командыКак правило, для выполнения каждой команды shell порождает отдельный процесс. Специальные команды отличаются тем, что они встроены в shell и выполняются в рамках текущего процесса.
: | Пустая команда. Возвращает нулевой код завершения. |
. file |
Shell читает и выполняет команды из
|