Реферат: Интерпретатор командного языка shell
Название: Интерпретатор командного языка 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. Синтаксис языка shell 2.1. Комментарии Строки, начинающиеся с #, трактуются как комментарии. 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". ${<переменная>:+<слово>} если <переменная> определена и не является пустой строкой, то подставляется <слово>; иначе подставляется пустая строка. Пример: если переменная в не определена или является пустой строкой, то выполняется команда pwd echo ${d:-`pwd`} Следующие переменные автоматически устанавливаются shell'ом:
Напомним: чтобы получить значения этих переменных, перед ними нужно поставить знак $. Пример: выдать номер текущего процесса: echo $$ 2.4. Специальные переменные Shell'ом используются следующие специальные переменные:
3. Управляющие конструкции Простая команда - это последовательность слов, разделенная пробелами. Первое слово является именем команды, которая будет выполняться, а остальные будут переданы ей как аргументы. Имя команды передается ей как аргумент номер 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 a do 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' ;; esac done 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 и выполняются в рамках текущего процесса.
4. Выполнение shell-программ 4.1. Запуск shell'а Программа, интерпретирующая shell-программы, находится в файле /bin/sh. При запуске ее первый аргумент является именем shell-программы, остальные передаются как позициональные параметры. Если файл, содержащий shell-программу, имеет право выполнения (x), то достаточно указания лишь его имени. Например, следующие две команды операционной системы эквивалентны (если файл ficofl обладает указанным правом и на самом деле содержит shell-программу): sh ficofl -d . g\* и ficofl -d . g\* 4.2. Выполнение При выполнении shell-программ выполняются все подстановки. Если имя команды совпадает с именем специальной команды, то она выполнается в рамках текущего процесса. Так же выполняются и определенные пользователем функции. Если имя команды не совпадает ни с именем специальной команды, ни с именем функции, то порождается новый процесс и осуществляется попытка выполнить указанную команду. Переменная PATH определяет путь поиска директории, содержащей данную команду. По умолчанию это ::/bin:/usr/ bin:/util:/dss/rk Директории поиска разделяются двоеточиями; :: означает текущую директорию. Если имя команды содержит символ /, значение $PATH не используется: имена, начинающиеся с / ищутся от корня, остальные - от текущей директории. Положение найденной команды запоминается shellом и может быть опрошено командой hash. 4.3. Окружение Окружение - это набор пар имя-значение, которые передаются выполняемой программе. Shell взаимодействует с окружением несколькими способами. При запуске shell создает переменную для каждой указанной пары, придавая ей соответствующее значение. Если вы измените значение какой-либо из этих переменных или создадите новую переменную, то это не окажет никакого влияния на окружение, если не будет использована команда export для связи переменной shell'а с окружением (см. также set -a). Переменная может быть удалена из окружения командой unset (см.). Таким образом, окружение каждой из выполняемых shell'ом команд формируется из всех неизмененных пар имя-значение, первоначально полученных shell'ом, минус пары, удаленные командой unset, плюс все модифицированные и измененные пары, которые для этого должны быть указаны в команде export. Окружение простых команд может быть сформировано указанием перед ней одного или нескольких присваиваний переменным. Так, TERM=d460 <команда> и (export TERM; TERM=d460; <команда>) эквивалентны. Переменные, участвующие в таких присваиваниях, назовем ключевыми параметрами. Если установлен флаг -k (см. set), то все ключевые параметры помещаются в окружение команды, даже если они записаны после команды. 4.4. Сигналы UNIX'ом поддерживаются следующие сигналы:
Сигналы SIGINT и SIGQUIT игнорируются, если команда была запущена асинхронно. Иначе сигналы обрабатываются так же, как в процессе-предке, за исключением сигнала SIGSEGV (см. также Специальные команды. Trap). 4.5. Замечания При выполнении команд запоминается их местонахождение. Поэтому при создании команды с тем же именем, но находящейся в другой директории, все равно будет выполняться старая команда (если вызов происходит по короткому имени). Для исправления ситуации воспользуйтесь командой hash с ключом -r (см. Специальные команды). Если вы переименовали текущую или вышележащую директорию, то команда pwd может давать неверную информацию. Для исправления ситуации воспользуйтесь командой cd с полным именем директории. 5. Дополнительные сведения 5.1. Команда test Команда test применяется для проверки условия. Формат вызова: test <выражение> или [ <выражение> ] Команда test вычисляет <выражение> и, если его значение - истина, возвращает код завершения 0 (true); иначе - ненулевое значение (false). Ненулевой код завершения возвращается и если опущены аргументы. <Выражение> может состоять из следующих примитивов:
5.2. Команда expr Команда expr применяется для вычисления выражений. Результат выводится на стандартный вывод. Операнды выражения должны быть разделены пробелами. Метасимволы должны быть экранированы. Надо заметить, что 0 возвращается в качестве числа, а не для индикации пустой строки. Строки, содержащие пробелы или другие специальные символы, должны быть заключены в кавычки. Целые рассматриваются как 32-битные числа. Ниже приведен список операторов в порядке возрастания приоритета, операции с равным приоритетом заключены в фигурные скобки. Перед символами, которые должны быть экранированы, стоит \.
Регулярное выражение строится следующим образом:
Все остальные символы (и ^, если стоит не в квадратных скобках) обозначают самих себя. Для указания символов ., *,[ и ] надо экранировать их (т.е. писать \., \*, \[, \]). Примеры. 1. a=`expr $a + 1` - увеличение на 1 переменной a 2. expr $a : '.*/\(.*\)' \| $a - выделяет из имени файла короткое имя (т.е. из /usr/util/ena выделяется ena). Внимание, одиночный символ / будет воспринят как знак операции деления. 3. expr $VAR : '.*' - получение количества символов переменной VAR. В качестве побочного эффекта expr возвращает следующие коды завершения:
Команда expr также выдает следующие сообщения об ошибках:
Замечание. Допустим, что мы хотим сравнить значение переменной a с каким-либо символом, имеющим для expr особый смысл, например, со знаком равенства. Пусть $a на самом деле является знаком равенства. Так как аргументы предварительно обрабатываются shell'ом, то команда expr $a = '=' будет воспринята как expr = = = что синтаксически некорректно. В подобных случаях надо пользоваться таким приемом: expr X$a = X= т.е. добавлением некоторого символа к обеим строкам, что никак не влияет на результат сравнения, однако позволяет избежать синтаксической ошибки. 5.3. Команда ena Команда ena позволяет получить части полного имени файла. Первый аргумент - флаг, второй - имя файла. Команда различает следующие флаги:
Ниже приводится текст программы ena, хранящийся в /util/ena. # Get part of pathname case $1 in -n ) expr $2 : '.*/\(.*\)[.].*' \| $2 : '\(.*\)[.].*' \| $2 ;; -f ) expr $2 : '.*/\(.*\)' \| $2 ;; -e ) expr $2 : '.*\([.][^./]*\)' \| ' ' ;; -d ) expr $2 : '\(.*\)/.*' \| $2 ;; -p ) expr $2 : '\([.]\)/.*' \| $2 : '\([.][.]\)/.*' \| ' ' ;; * ) echo "error: unknown part of pathname $1" exit 2 ;; esac |