Страница:
вызывает интерпретатор для выполнения команд из файла file.
Если в командной строке заданы параметры, они передаются
- 15 -
порождаемому процессу в виде значений макропеременных "1",
"2" и т.д.
Например, если файл wg содержит строку:
who | grep $1
то команда
sh wg nata
выполняет действие эквивалентное
who | grep nata
Признак того, что файл можно выполнять обычно устанав-
ливает компонента, создавшая данный файл (например компиля-
тор). Командные файлы, как правило, создаются непосредст-
венно пользователем и данного признака не содержат. Поэтому
возникает необходимость установить для файла признак выпол-
нение разрешено. Для этого можно использовать команду chmod.
Например, в результате работы команды:
chmod +х wg
файл wg получает признак выполнение разрешено.
Обработка параметров при запуске команды выполняется по
следующим правилам:
- Обрабатываются все имеющиеся метасимволы языка.
- Командная строка разбивается на слова - последователь-
ности символов, не содержащие символов-разделителей, к
которым относятся пробел, символ начала строки и знак
табуляции. Если в качестве параметра требуется пере-
дать текст, который содержит пробелы, он берется в
кавычки.
- Выделенные слова последовательно присваиваются макропе-
ременным с именами "0", "1", "2", и т.д.
- В качестве значения макропеременной "#" устанавливается
число параметров.
- Значения всех параметров (за исключением нулевого)
присваиваются макропеременой *. Т.е. макровызов $*
будет заменяться на строку, содержащую значения всех
параметров.
Например, если командный файл show имеет вид:
- 16 -
echo '
Команда $0 =' $0 '
Значение $1 =' $1 '
Значение $2 =' $2 '
Число параметров =' $# '
Значение $* =' $*
то в результате выполнения команды:
show первый второй
будет получен следующий текст:
Команда $0 = show
Значение $1 = первый
Значение $2 = второй
Число параметров = 2
Значение $* = первый второй
3.1. Комментарии
В командной строке языка SHELL можно использовать коммента-
рий, который служит для улучшения читаемости командных фай-
лов. Комментарий должен начинаться символом # и распола-
гаться в конце командной строки. Так как часть строки, сле-
дующая за символом #, не рассматривается интерпретатором, в
ней могут встречаться любые символы.
Например:
# Это пример комментария
ls # Будет выполнена команда
# ls (это тоже комментарий)
Следует помнить, что если # является первым символом файла,
ему придается особый смысл - это признак того, что должен
использоваться интерпретатор языка csh.
3.2. Команда test
Команда test, хотя и не является конструкцией языка
SHELL, необходима при создании командных файлов. В резуль-
тате выполнения команды осуществляется проверка заданного
условия и сообщается код ее завершения, который может
использоваться в операторах условного перехода и цикла.
Например, код завершения команды
test -f file
равен нулю, если файл file существует, и не равен нулю - в
противном случае.
- 17 -
Основные возможности команды можно проиллюстрировать на
следующих примерах:
test s
истинно, если аргумент s не является пустой строкой;
test -f file
истинно, если файл существует;
test -r file
истинно, если файл можно читать;
test -w file
истинно, если в файл можно писать;
test -d file
истинно, если файл является справочником.
3.3. Оператор for
В языке SHELL существует возможность последовательного
повторения какой-либо группы команд для каждого элемента
указанного списка. Для этой цели используется оператор
цикла for, который имеет следующий формат:
for имя [in слово1 слово2 ...]
do список_команд
done
где список_команд - это последовательность одной или нес-
кольких простых команд, разделенных символами ; или перечис-
ленных на разных строках. Зарезервированные слова do и done
распознаются только в том случае, если они следуют за симво-
лом новой строки или точки с запятой. Имя - это макропере-
менная языка SHELL, которая в процессе выполнения
списка_команд последовательно принимает значения слово1
слово2 .... Если конструкция in слово1 слово2 ... отсутст-
вует, то цикл выполняется один раз для каждого заданного
параметра (т.е. по умолчанию предполагается in $*). В
качестве примера можно привести команду tel, которая прос-
матривает файл /usr/lib/pfone, содержащий строки вида:
...
Иванов И.И. 224 01 01
Петров П.П. 123 07 07
Сизов В.И. 224 44 94
...
Текст процедуры tel:
for i
do grep $i usr/lib/pfone; done
- 18 -
В результате выполнения команды:
tel Петров
будут напечатаны те строки файла /usr/lib/pfone, которые
содержат последовательность символов Петров, а команда:
tel Иванов Петров
напечатает сначала строки, содержащие последовательность
символов Иванов, а затем те строки, которые содержат символы
Петров.
Еще одним примером использования цикла for является
командный файл create:
for i do >> $i; done
Результатом выполнения команды
create alpha beta
является создание двух пустых файлов alpha и beta.
3.4. Оператор case
Рассмотрим в качестве примера командный файл add,
содержащий следующий текст:
case $# in
1) cat >>>> $1;;
2) cat >>>> $2 << $1;;
*) echo 'Формат: add [откуда] куда';;
esac
При вызове команды с одним аргументом, например:
add file
параметр $# получает значение '1', и команда cat копирует
информацию из стандартного файла ввода в конец файла file.
Команда:
add file1 file2
допишет содержимое файла file1 в конец файла file2. Если
число параметров, передаваемых команде add, отлично от 1 и
от 2, то печатается сообщение "Формат: add куда [откуда]".
Формат оператора case:
- 19 -
case слово in
[образец[|образец] ...) список_команд;;]
...
[образец[|образец] ...) список_команд[;;]]
esac
Интерпретатор последовательно сравнивает слово с каждым
из указанных образцов. При обнаружении соответствия выполня-
ется записанный при образце список_команд, после чего, обра-
ботка оператора завершается. Символ * представляет собой
образец, который соответствует любой строке. Каждый
список_команд (за исключением последнего) необходимо завер-
шать символами ;;.
Первое же совпадение слова с образцом полностью опреде-
ляет множество выполняемых команд. В следующем примере
команды, указанные за вторым символом *, не будут выпол-
няться никогда:
case $# in
*) ...;;
*) ...;;
esac
Оператор case часто используется для проверки коррект-
ности параметров. Это можно проиллюстрировть следующим фраг-
ментом команды cc:
for i
do case $i in
-[ocs]) ...;;
-*) echo 'неизвестный ключ $i';;
*.c) lib/c0 $i ...;;
*) echo 'неизвестный параметр $i';;
esac
done
Если условием выполнения какого-либо списка_команд
является группа образцов, то при их перечислении в команде
case в качестве разделителя используется символ |. Так,
оператор:
case $i in
-х) echo $i
-y) echo $i
esac
может быть записан слудующим образом:
- 20 -
case $i in
-х|-y) echo $i
esac
При поиске соответствующего образца применимы основные
соглашения об отмене специального значения метасимволов, так
образец в конструкции:
case $i in
?) ...
будет соответствовать символу ?.
3.5. Операторы while и until
Оператор while предназначен для организации циклов,
выполнение которых производится до тех пор, пока код завер-
шения указанного списка команд равен нулю.
Общая форма оператора while:
while список_команд_1
[do список_команд_2]
done
В каждом цикле выполняются команды из списка_команд_1.
Оператор while проверяет код завершения последней простой
команды из этого списка: если он равен нулю, выполняется
список_команд_2 и цикл повторяется, иначе - выполнение цикла
завершается.
Например, при выполнения следующих операторов:
while test $1
do ...
shift
done
и
for i
do ...
done
будет получен одинаковый результат.
Оператор shift переименовывает позиционные параметры
"2, 3, ..." в параметры "1, 2, ..." соответственно; значение
параметра "1" теряется.
- 21 -
Другим способом организации цикла является использова-
ние оператора until:
until список_команд_1
[do список_команд_2]
done
В отличие от while цикл until будет выполняться до тех пор,
пока код завершения последней команды списка_команд_1 не
будет иметь нулевое значение.
3.6. Операторы break и continue
Операторы break и continue используются в конструкциях
for, while и until.
Оператор break прерывает работу цикла, в теле которого
он выполняется. В качестве примера можно привести прог-
рамму, которая выдает значения своих параметров, расположен-
ных до символа %:
for i
do
case $i in
%) break;;
*) echo $i;;
esac
done
Оператор continue осуществляет переход к следующей ите-
рации цикла. Для примера рассмотрим командный файл, который
выводит только те параметры, которые начинаются с буквы:
for i
do
case $i in
[А-Яа-я]*) echo $i;;
[A-Za-z]*) echo $i;;
*) continue;;
esac
done
3.7. Оператор if
Условный оператор вида:
if список_команд_1
then список_команд_2
[else список_команд_3]
fi
- 22 -
проверяет код завершения последней простой команды
списка_команд_1: если он равен нулю, выполняется
список_команд_2, иначе - список_команд_3.
Команда if может использоваться совместно с командой
test, например, для проверки существования файла:
if test -f $1
then echo "ФАЙЛ $1 СУЩЕСТВУЕТ"
else echo "ФАЙЛ $1 НЕ СУЩЕСТВУЕТ"
fi
При многократном повторении условного оператора, напри-
мер:
if ...
then ...
else ...
if ...
then ...
else if ...
...
fi
fi
fi
можно использовать сокращенную запись:
if ...
then ...
elif ...
then ...
elif ...
...
fi
Конструкция
if команда1
then команда2
fi
может быть записана в виде:
команда1 && команда2
В конструкции
команда1 || команда2
команда2 выполняется только в том случае, если команда1 не
- 23 -
была выполнена успешно. Кодом завершения обеих конструкций
является код завершения последней простой команды.
3.8. Локальный файл
В процедуре tel, рассмотренной в ранее, исходные данные
для команды grep берутся из файла /usr/lib/pfone. Обрабаты-
ваемые данные могут непосредственно включаться в командный
файл. Для этого они оформляются в виде локального файла. В
следующем примере:
for i
do grep $i <<<<!
...
Иванов И.И. 224 01 01
Петров П.П. 123 07 07
Сизов В.И. 224 44 94
...
!
done
строки, заключенные между символами <<<<! и !, передаются
команде grep в качестве данных стандартного файла ввода.
Строка-ограничитель ! выбрана здесь произвольно: главное,
чтобы она совпадала с последовательностью символов, стоящей
за знаками <<<<.
Если следующая за <<<< последовательность символов не
начинается со знака \, то прежде чем локальный файл станет
доступным командe, в нем выполняются все подстановки пара-
метров.
Например, пусть файл edg содержит строки вида:
ed $3 <<<< %
g/$1/s//$2/g
w
%
при вызове:
edg строка1 строка2 file
будет достигнут результат, который можно получить при выпол-
нении следующей последовательности команд:
ed file <<<< %
g/строка1/s//строка2/g
w
%
- 24 -
3.9. Отладка командных файлов
В SHELL используются два механизма отладки командных
файлов. Первый из них:
set -v
выводит строки командного файла по мере их чтения. Этот
режим применяется при поиске синтаксических ошибок. Для его
использования не требуется производить модификацию команд-
ного файла, например:
sh -v proc...
здесь proc - имя командного файла. Ключ -v может использо-
ваться вместе с ключом -n, предотвращающим выполнение следу-
ющих за ним команд (команда set -n блокирует терминал до тех
пор, пока не вводится признак конца файла EOF).
Команда
set -х
выводит команды по мере их выполнения. Для отмены ключей -x
и -v можно воспользоваться командой
set -
а для установки - присвоить соответствующее значение макро-
переменной -.
4. ПАРАМЕТРЫ И ОБЛАСТЬ ДЕЙСТВИЯ МАКРОПЕРЕМЕННЫХ
Макропеременные, определенные в одном процессе, при
отсутствии явных указаний не доступны в других процессах.
Для того чтобы обеспечить возможность передачи порождаемому
процессу какой-либо информации, в языке предусмотренны
средства, которые позволяют:
- передавать команде параметры;
- экспортировать определения макропеременных из среды
текущего процесса в среду порождаемого;
- определять макропеременные и передавать их определения
в среду порождаемого процесса без изменения среды теку-
щего.
Так, в следующем примере:
USER=nata команда
перед выполнением файла команда макропеременная USER
- 25 -
принимает значение nata. При использовании флага -k опера-
торы вида имя=значение могут вставляться в любое место
списка параметров. Такие имена называются ключевыми пара-
метрами. Значения параметров присваиваются макропеременным
с именами "1", "2", ... N (поскольку число в имени макропе-
ременной указывает позицию параметра в командной строке,
такие параметры называются позиционными).
Для того чтобы присвоить значения позиционным парамет-
рам непосредственно из командного файла используется команда
set. Так, в следующем примере
set *
параметру "1" будет присвоено значение имени первого файла
текущего справочника, параметру "2" - имя второго файла и
т.д.
При выполнении команд интерпретатор производит следую-
щие действия:
- Подстановка значений параметров, например:
$user
- Подстановка результатов выполнения команд, например:
`pwd`
В тех случаях, когда в строке требуется выполнить нес-
колько вложенных макроподстановок, используется встро-
енная команда eval. Например, если значением макропере-
менной X является строка $y, а макропеременной y - pqr,
то команда
eval echo $X
выдаст строку pqr.
Результаты выполнения команды eval являются входными
данными для SHELL, который считывает их и выполняет в
качестве команд. Таким образом, конструкция
wg='eval who | grep'
$wg fred
эквивалентна команде
who | grep fred
- 26 -
В этом примере без команды eval не обойтись, так как
метасимвол | при последующей макроподстановке не
интерпретируется.
- Интерпретация символов-разделителей.
Символы, полученные в результате выполнения указанных
выше подстановок, разбиваются затем на слова, не содер-
жащие разделителей. Пробелами здесь названы символы,
являющиеся разделителями слов. Список этих символов
содержится в макропеременной IFS; по умолчанию к ним
относятся пробел, символы горизонтальной табуляции и
новой строки. Если специальное значение пробела отме-
нить одним из существующих способов, то он будет
интерпретироваться соответствующей последовательностью
символов. Например, командa
echo ''
будет выдавать пустую строку, поскольку она является
первым аргументом команды echo, в то время как вызов
команды
echo $null
будет осуществляться без аргументов, если значение мак-
ропеременной null не определено или определено как
пустая строка.
- Задание имен файлов.
На этом этапе в словах осуществляется поиск символов *,
? и [...] (являющихся образцами имен файлов) и замена
каждого слова списком имен файлов, расположенных в
алфавитном порядке. Каждое имя файла рассматривается
как отдельный параметр.
Над словами, содержащимися в операторе цикла for,
выполняются все перечисленные действия. В опрераторе case
выполняется только подстановка значения параметра, указывае-
мого после ключевого слова case.
Как отмечалось, в языке SHELL существуют три механизма
экранирования метасимволов (с использованием символов \,
'...' и "..."). Внутри строк, заключенных в двойные кавычки,
выполняются только подстановки значений параметров и резуль-
татов выполнения команд. Далее перечислены символы, которые
при заключении их в двойные кавычки не теряют своего специ-
ального значения:
- 27 -
$ подстановка значений параметров;
` подстановка результатов выполнения команд;
ограничитель экранируемой строки;
\ экранирует метасимволы $, `, " и \.
Например, в команде
echo $х
значение макропеременной x является единственным аргументом.
Аналогично, в команде
echo $*
все позиционные параметры рассматриваются в качестве единст-
венного аргумента; эта команда эквивалентна следующей:
echo $1 $2 ...
Макровызовы $@ и $* идентичны, за исключением способов их
экранирования. Команды
echo $@
и
echo $1 $2 ...
эквивалентны. В результате их выполнения будут выдаваться
значения всех позиционных параметров.
На рисунке 1 показано воздействие механизмов экраниро-
вания на каждый из метасимволов языка SHELL.
Метасимволы
$ * ` " '
-|------------------|
' | - - - - - t |
` | + - - t - - |
" | + + - + t - |
_|__________________|
+ метасимвол экранируется;
- метасимвол не экранируется;
t ограничитель экранируемой строки.
Рис.1
- 28 -
4.1. Передача параметров
Как позиционные, так и ключевые параметры могут быть
получены в процессе вызова командного файла. Ключевые пара-
метры, кроме того, можно сделать доступными еще одним спосо-
бом: нужно явно указать, что они вводятся в среду процесса
(становятся макропеременными). Например, команда:
export USER BOX
указывает на то, что такими макропеременными являются USER и
BOX. При вызове командного файла создаются копии всех мак-
ропеременных. Изменение значений макропеременных не вызывает
их модификации в порождающем процессе. Командный файл не
может изменить состояние порождающего процесса без явного
вызова со стороны порождающего процесса. (Исключение сос-
тавляют дескрипторы распределенных файлов).
Имена макропеременных, имеющих постоянные значения,
могут задаваться с помощью команды readonly (только для чте-
ния). Формат этой команды совпадает с форматом команды
export:
readonly имя...
После выполнения этой команды значения перечисленных макро-
переменных больше изменить нельзя.
4.2. Подстановка значений параметров
Если параметру языка SHELL не было присвоено значение,
то он определяется как пустая строка. При выполнении
команды
echo ${d-.}
выдается значение макропеременной d, если она определена,
или символ '.' - в противном случае. В команде echo исполь-
зуются обычные соглашения об отмене специальных значений
метасимволов. Следовательно, если значение макропеременной d
не было определено, то команда
echo ${d-'*'}
выведет символ *. Аналогично, команда
echo ${d-$X}
если макропеременная d определена, выдаст ее значение, если
нет - значение макропеременной X.
Значение по умолчанию макропеременной может быть опре-
делено следующим образом:
- 29 -
echo ${d=.}
если макропеременная d не определена, ей присваивается сим-
вол '.' (для позиционных параметров обозначение ${...=...}
использовать нельзя).
Команда
echo ${d?сообщение}
выдает значение макропеременной d, если оно определено, и
сообщение - если не определено. В последнем случае выполне-
ние командного файла завершается. Если сообщение отсутст-
вует, то выдается стандартная диагностика интерпретатора.
Командный файл, часть параметров которого должна иметь опре-
деленные значения, может начинаться следующим образом:
: ${USER?} ${HOME?} ${BIN?}
...
Двоеточие : представляет собой встроенную команду языка
SHELL, предназначенную для оценки значений своих параметров.
Если значение хотя бы одной из переменных USER, HOME или BIN
не определено, выдается диагностика и выполнение командного
файла прекращается.
4.3. Подстановка результатов выполнения команд
В языке SHELL существует возможность использования
результата выполнения команд в различных целях. Так, стан-
дартным выходом команды pwd является имя текущего справоч-
ника, и если таким справочником является, например,
/usr/nata/bin, то команда
d=`pwd`
будет эквивалентна команде
d=/usr/nata/bin
Строка, заключенная между обратными кавычками `...`, воспри-
нимается как команда и заменяется результатом выполнения
этой команды. Команды записываются с использованием обычных
соглашений об отмене специальных значений метасимволов, за
исключением того, что специальное значение символа обратной
кавычки "`" отменяется символом \. Например, команда
ls `echo $1`
эквивалентна команде
ls $1
- 30 -
Везде, где разрешена подстановка значений параметров,
может производиться и подстановка результатов выполнения
команд (в том числе и в локальных файлах). Обработка резуль-
татов в обоих случаях выполняется одинаково. Это позволяет
использовать в процедурах языка SHELL команды, предназначен-
ные для обработки строк. Примером такой команды является
команда basename, которая удаляет из слова указанный суф-
фикс. Например, в результате выполнения команды
basename main.c .c
будет получена последовательность символов main. Использова-
ние команды basename можно проиллюстрировать следующим фраг-
ментом команды cc:
case $A in
...
*.c) B=`basename $A .c`
...
esac
В этом примере макропеременной B присваивается значение мак-
ропеременной A, из которой удален суффикс .c.
4.4. Обработка ошибок
Действия интерпретатора при обнаружении ошибки зависят
от двух обстоятельств: типа ошибки и режима работы интерпре-
татора. Режим работы интерпретатора считается интерактивным
в том случае, если ввод/вывод информации осуществляется с
терминала или интерпретатор вызван с ключом -i.
Приведем список причин, которые приводят к ошибкам при
выполнении команды:
- неверное указание файлов ввода/вывода (например, файл
не существует или не может быть создан);
- самой команды не существует, или она не может быть
выполнена;
- команда вызвалась нормально, но ее код завершения
имеет ненулевое значение.
Если интерпретатор работает в интерактивном режиме, то,
независимо от результата завершения предыдущей команды, он
переходит к выполнению следующей.
В не интерактивном режиме два вида ошибок приводят к
прекращению обработки командного файла:
- синтаксическая ошибка в операторах управления (while,
until, if, for);
- 31 -
- ошибка при выполнении встроенной команды.
Для того чтобы обеспечить прекращение выполнения
команды при обнаружении любой из указанных ошибок, при
вызове интерпретатора необходимо использовать ключ -e.
4.5. Обработка прерываний
Если в командной строке заданы параметры, они передаются
- 15 -
порождаемому процессу в виде значений макропеременных "1",
"2" и т.д.
Например, если файл wg содержит строку:
who | grep $1
то команда
sh wg nata
выполняет действие эквивалентное
who | grep nata
Признак того, что файл можно выполнять обычно устанав-
ливает компонента, создавшая данный файл (например компиля-
тор). Командные файлы, как правило, создаются непосредст-
венно пользователем и данного признака не содержат. Поэтому
возникает необходимость установить для файла признак выпол-
нение разрешено. Для этого можно использовать команду chmod.
Например, в результате работы команды:
chmod +х wg
файл wg получает признак выполнение разрешено.
Обработка параметров при запуске команды выполняется по
следующим правилам:
- Обрабатываются все имеющиеся метасимволы языка.
- Командная строка разбивается на слова - последователь-
ности символов, не содержащие символов-разделителей, к
которым относятся пробел, символ начала строки и знак
табуляции. Если в качестве параметра требуется пере-
дать текст, который содержит пробелы, он берется в
кавычки.
- Выделенные слова последовательно присваиваются макропе-
ременным с именами "0", "1", "2", и т.д.
- В качестве значения макропеременной "#" устанавливается
число параметров.
- Значения всех параметров (за исключением нулевого)
присваиваются макропеременой *. Т.е. макровызов $*
будет заменяться на строку, содержащую значения всех
параметров.
Например, если командный файл show имеет вид:
- 16 -
echo '
Команда $0 =' $0 '
Значение $1 =' $1 '
Значение $2 =' $2 '
Число параметров =' $# '
Значение $* =' $*
то в результате выполнения команды:
show первый второй
будет получен следующий текст:
Команда $0 = show
Значение $1 = первый
Значение $2 = второй
Число параметров = 2
Значение $* = первый второй
3.1. Комментарии
В командной строке языка SHELL можно использовать коммента-
рий, который служит для улучшения читаемости командных фай-
лов. Комментарий должен начинаться символом # и распола-
гаться в конце командной строки. Так как часть строки, сле-
дующая за символом #, не рассматривается интерпретатором, в
ней могут встречаться любые символы.
Например:
# Это пример комментария
ls # Будет выполнена команда
# ls (это тоже комментарий)
Следует помнить, что если # является первым символом файла,
ему придается особый смысл - это признак того, что должен
использоваться интерпретатор языка csh.
3.2. Команда test
Команда test, хотя и не является конструкцией языка
SHELL, необходима при создании командных файлов. В резуль-
тате выполнения команды осуществляется проверка заданного
условия и сообщается код ее завершения, который может
использоваться в операторах условного перехода и цикла.
Например, код завершения команды
test -f file
равен нулю, если файл file существует, и не равен нулю - в
противном случае.
- 17 -
Основные возможности команды можно проиллюстрировать на
следующих примерах:
test s
истинно, если аргумент s не является пустой строкой;
test -f file
истинно, если файл существует;
test -r file
истинно, если файл можно читать;
test -w file
истинно, если в файл можно писать;
test -d file
истинно, если файл является справочником.
3.3. Оператор for
В языке SHELL существует возможность последовательного
повторения какой-либо группы команд для каждого элемента
указанного списка. Для этой цели используется оператор
цикла for, который имеет следующий формат:
for имя [in слово1 слово2 ...]
do список_команд
done
где список_команд - это последовательность одной или нес-
кольких простых команд, разделенных символами ; или перечис-
ленных на разных строках. Зарезервированные слова do и done
распознаются только в том случае, если они следуют за симво-
лом новой строки или точки с запятой. Имя - это макропере-
менная языка SHELL, которая в процессе выполнения
списка_команд последовательно принимает значения слово1
слово2 .... Если конструкция in слово1 слово2 ... отсутст-
вует, то цикл выполняется один раз для каждого заданного
параметра (т.е. по умолчанию предполагается in $*). В
качестве примера можно привести команду tel, которая прос-
матривает файл /usr/lib/pfone, содержащий строки вида:
...
Иванов И.И. 224 01 01
Петров П.П. 123 07 07
Сизов В.И. 224 44 94
...
Текст процедуры tel:
for i
do grep $i usr/lib/pfone; done
- 18 -
В результате выполнения команды:
tel Петров
будут напечатаны те строки файла /usr/lib/pfone, которые
содержат последовательность символов Петров, а команда:
tel Иванов Петров
напечатает сначала строки, содержащие последовательность
символов Иванов, а затем те строки, которые содержат символы
Петров.
Еще одним примером использования цикла for является
командный файл create:
for i do >> $i; done
Результатом выполнения команды
create alpha beta
является создание двух пустых файлов alpha и beta.
3.4. Оператор case
Рассмотрим в качестве примера командный файл add,
содержащий следующий текст:
case $# in
1) cat >>>> $1;;
2) cat >>>> $2 << $1;;
*) echo 'Формат: add [откуда] куда';;
esac
При вызове команды с одним аргументом, например:
add file
параметр $# получает значение '1', и команда cat копирует
информацию из стандартного файла ввода в конец файла file.
Команда:
add file1 file2
допишет содержимое файла file1 в конец файла file2. Если
число параметров, передаваемых команде add, отлично от 1 и
от 2, то печатается сообщение "Формат: add куда [откуда]".
Формат оператора case:
- 19 -
case слово in
[образец[|образец] ...) список_команд;;]
...
[образец[|образец] ...) список_команд[;;]]
esac
Интерпретатор последовательно сравнивает слово с каждым
из указанных образцов. При обнаружении соответствия выполня-
ется записанный при образце список_команд, после чего, обра-
ботка оператора завершается. Символ * представляет собой
образец, который соответствует любой строке. Каждый
список_команд (за исключением последнего) необходимо завер-
шать символами ;;.
Первое же совпадение слова с образцом полностью опреде-
ляет множество выполняемых команд. В следующем примере
команды, указанные за вторым символом *, не будут выпол-
няться никогда:
case $# in
*) ...;;
*) ...;;
esac
Оператор case часто используется для проверки коррект-
ности параметров. Это можно проиллюстрировть следующим фраг-
ментом команды cc:
for i
do case $i in
-[ocs]) ...;;
-*) echo 'неизвестный ключ $i';;
*.c) lib/c0 $i ...;;
*) echo 'неизвестный параметр $i';;
esac
done
Если условием выполнения какого-либо списка_команд
является группа образцов, то при их перечислении в команде
case в качестве разделителя используется символ |. Так,
оператор:
case $i in
-х) echo $i
-y) echo $i
esac
может быть записан слудующим образом:
- 20 -
case $i in
-х|-y) echo $i
esac
При поиске соответствующего образца применимы основные
соглашения об отмене специального значения метасимволов, так
образец в конструкции:
case $i in
?) ...
будет соответствовать символу ?.
3.5. Операторы while и until
Оператор while предназначен для организации циклов,
выполнение которых производится до тех пор, пока код завер-
шения указанного списка команд равен нулю.
Общая форма оператора while:
while список_команд_1
[do список_команд_2]
done
В каждом цикле выполняются команды из списка_команд_1.
Оператор while проверяет код завершения последней простой
команды из этого списка: если он равен нулю, выполняется
список_команд_2 и цикл повторяется, иначе - выполнение цикла
завершается.
Например, при выполнения следующих операторов:
while test $1
do ...
shift
done
и
for i
do ...
done
будет получен одинаковый результат.
Оператор shift переименовывает позиционные параметры
"2, 3, ..." в параметры "1, 2, ..." соответственно; значение
параметра "1" теряется.
- 21 -
Другим способом организации цикла является использова-
ние оператора until:
until список_команд_1
[do список_команд_2]
done
В отличие от while цикл until будет выполняться до тех пор,
пока код завершения последней команды списка_команд_1 не
будет иметь нулевое значение.
3.6. Операторы break и continue
Операторы break и continue используются в конструкциях
for, while и until.
Оператор break прерывает работу цикла, в теле которого
он выполняется. В качестве примера можно привести прог-
рамму, которая выдает значения своих параметров, расположен-
ных до символа %:
for i
do
case $i in
%) break;;
*) echo $i;;
esac
done
Оператор continue осуществляет переход к следующей ите-
рации цикла. Для примера рассмотрим командный файл, который
выводит только те параметры, которые начинаются с буквы:
for i
do
case $i in
[А-Яа-я]*) echo $i;;
[A-Za-z]*) echo $i;;
*) continue;;
esac
done
3.7. Оператор if
Условный оператор вида:
if список_команд_1
then список_команд_2
[else список_команд_3]
fi
- 22 -
проверяет код завершения последней простой команды
списка_команд_1: если он равен нулю, выполняется
список_команд_2, иначе - список_команд_3.
Команда if может использоваться совместно с командой
test, например, для проверки существования файла:
if test -f $1
then echo "ФАЙЛ $1 СУЩЕСТВУЕТ"
else echo "ФАЙЛ $1 НЕ СУЩЕСТВУЕТ"
fi
При многократном повторении условного оператора, напри-
мер:
if ...
then ...
else ...
if ...
then ...
else if ...
...
fi
fi
fi
можно использовать сокращенную запись:
if ...
then ...
elif ...
then ...
elif ...
...
fi
Конструкция
if команда1
then команда2
fi
может быть записана в виде:
команда1 && команда2
В конструкции
команда1 || команда2
команда2 выполняется только в том случае, если команда1 не
- 23 -
была выполнена успешно. Кодом завершения обеих конструкций
является код завершения последней простой команды.
3.8. Локальный файл
В процедуре tel, рассмотренной в ранее, исходные данные
для команды grep берутся из файла /usr/lib/pfone. Обрабаты-
ваемые данные могут непосредственно включаться в командный
файл. Для этого они оформляются в виде локального файла. В
следующем примере:
for i
do grep $i <<<<!
...
Иванов И.И. 224 01 01
Петров П.П. 123 07 07
Сизов В.И. 224 44 94
...
!
done
строки, заключенные между символами <<<<! и !, передаются
команде grep в качестве данных стандартного файла ввода.
Строка-ограничитель ! выбрана здесь произвольно: главное,
чтобы она совпадала с последовательностью символов, стоящей
за знаками <<<<.
Если следующая за <<<< последовательность символов не
начинается со знака \, то прежде чем локальный файл станет
доступным командe, в нем выполняются все подстановки пара-
метров.
Например, пусть файл edg содержит строки вида:
ed $3 <<<< %
g/$1/s//$2/g
w
%
при вызове:
edg строка1 строка2 file
будет достигнут результат, который можно получить при выпол-
нении следующей последовательности команд:
ed file <<<< %
g/строка1/s//строка2/g
w
%
- 24 -
3.9. Отладка командных файлов
В SHELL используются два механизма отладки командных
файлов. Первый из них:
set -v
выводит строки командного файла по мере их чтения. Этот
режим применяется при поиске синтаксических ошибок. Для его
использования не требуется производить модификацию команд-
ного файла, например:
sh -v proc...
здесь proc - имя командного файла. Ключ -v может использо-
ваться вместе с ключом -n, предотвращающим выполнение следу-
ющих за ним команд (команда set -n блокирует терминал до тех
пор, пока не вводится признак конца файла EOF).
Команда
set -х
выводит команды по мере их выполнения. Для отмены ключей -x
и -v можно воспользоваться командой
set -
а для установки - присвоить соответствующее значение макро-
переменной -.
4. ПАРАМЕТРЫ И ОБЛАСТЬ ДЕЙСТВИЯ МАКРОПЕРЕМЕННЫХ
Макропеременные, определенные в одном процессе, при
отсутствии явных указаний не доступны в других процессах.
Для того чтобы обеспечить возможность передачи порождаемому
процессу какой-либо информации, в языке предусмотренны
средства, которые позволяют:
- передавать команде параметры;
- экспортировать определения макропеременных из среды
текущего процесса в среду порождаемого;
- определять макропеременные и передавать их определения
в среду порождаемого процесса без изменения среды теку-
щего.
Так, в следующем примере:
USER=nata команда
перед выполнением файла команда макропеременная USER
- 25 -
принимает значение nata. При использовании флага -k опера-
торы вида имя=значение могут вставляться в любое место
списка параметров. Такие имена называются ключевыми пара-
метрами. Значения параметров присваиваются макропеременным
с именами "1", "2", ... N (поскольку число в имени макропе-
ременной указывает позицию параметра в командной строке,
такие параметры называются позиционными).
Для того чтобы присвоить значения позиционным парамет-
рам непосредственно из командного файла используется команда
set. Так, в следующем примере
set *
параметру "1" будет присвоено значение имени первого файла
текущего справочника, параметру "2" - имя второго файла и
т.д.
При выполнении команд интерпретатор производит следую-
щие действия:
- Подстановка значений параметров, например:
$user
- Подстановка результатов выполнения команд, например:
`pwd`
В тех случаях, когда в строке требуется выполнить нес-
колько вложенных макроподстановок, используется встро-
енная команда eval. Например, если значением макропере-
менной X является строка $y, а макропеременной y - pqr,
то команда
eval echo $X
выдаст строку pqr.
Результаты выполнения команды eval являются входными
данными для SHELL, который считывает их и выполняет в
качестве команд. Таким образом, конструкция
wg='eval who | grep'
$wg fred
эквивалентна команде
who | grep fred
- 26 -
В этом примере без команды eval не обойтись, так как
метасимвол | при последующей макроподстановке не
интерпретируется.
- Интерпретация символов-разделителей.
Символы, полученные в результате выполнения указанных
выше подстановок, разбиваются затем на слова, не содер-
жащие разделителей. Пробелами здесь названы символы,
являющиеся разделителями слов. Список этих символов
содержится в макропеременной IFS; по умолчанию к ним
относятся пробел, символы горизонтальной табуляции и
новой строки. Если специальное значение пробела отме-
нить одним из существующих способов, то он будет
интерпретироваться соответствующей последовательностью
символов. Например, командa
echo ''
будет выдавать пустую строку, поскольку она является
первым аргументом команды echo, в то время как вызов
команды
echo $null
будет осуществляться без аргументов, если значение мак-
ропеременной null не определено или определено как
пустая строка.
- Задание имен файлов.
На этом этапе в словах осуществляется поиск символов *,
? и [...] (являющихся образцами имен файлов) и замена
каждого слова списком имен файлов, расположенных в
алфавитном порядке. Каждое имя файла рассматривается
как отдельный параметр.
Над словами, содержащимися в операторе цикла for,
выполняются все перечисленные действия. В опрераторе case
выполняется только подстановка значения параметра, указывае-
мого после ключевого слова case.
Как отмечалось, в языке SHELL существуют три механизма
экранирования метасимволов (с использованием символов \,
'...' и "..."). Внутри строк, заключенных в двойные кавычки,
выполняются только подстановки значений параметров и резуль-
татов выполнения команд. Далее перечислены символы, которые
при заключении их в двойные кавычки не теряют своего специ-
ального значения:
- 27 -
$ подстановка значений параметров;
` подстановка результатов выполнения команд;
ограничитель экранируемой строки;
\ экранирует метасимволы $, `, " и \.
Например, в команде
echo $х
значение макропеременной x является единственным аргументом.
Аналогично, в команде
echo $*
все позиционные параметры рассматриваются в качестве единст-
венного аргумента; эта команда эквивалентна следующей:
echo $1 $2 ...
Макровызовы $@ и $* идентичны, за исключением способов их
экранирования. Команды
echo $@
и
echo $1 $2 ...
эквивалентны. В результате их выполнения будут выдаваться
значения всех позиционных параметров.
На рисунке 1 показано воздействие механизмов экраниро-
вания на каждый из метасимволов языка SHELL.
Метасимволы
$ * ` " '
-|------------------|
' | - - - - - t |
` | + - - t - - |
" | + + - + t - |
_|__________________|
+ метасимвол экранируется;
- метасимвол не экранируется;
t ограничитель экранируемой строки.
Рис.1
- 28 -
4.1. Передача параметров
Как позиционные, так и ключевые параметры могут быть
получены в процессе вызова командного файла. Ключевые пара-
метры, кроме того, можно сделать доступными еще одним спосо-
бом: нужно явно указать, что они вводятся в среду процесса
(становятся макропеременными). Например, команда:
export USER BOX
указывает на то, что такими макропеременными являются USER и
BOX. При вызове командного файла создаются копии всех мак-
ропеременных. Изменение значений макропеременных не вызывает
их модификации в порождающем процессе. Командный файл не
может изменить состояние порождающего процесса без явного
вызова со стороны порождающего процесса. (Исключение сос-
тавляют дескрипторы распределенных файлов).
Имена макропеременных, имеющих постоянные значения,
могут задаваться с помощью команды readonly (только для чте-
ния). Формат этой команды совпадает с форматом команды
export:
readonly имя...
После выполнения этой команды значения перечисленных макро-
переменных больше изменить нельзя.
4.2. Подстановка значений параметров
Если параметру языка SHELL не было присвоено значение,
то он определяется как пустая строка. При выполнении
команды
echo ${d-.}
выдается значение макропеременной d, если она определена,
или символ '.' - в противном случае. В команде echo исполь-
зуются обычные соглашения об отмене специальных значений
метасимволов. Следовательно, если значение макропеременной d
не было определено, то команда
echo ${d-'*'}
выведет символ *. Аналогично, команда
echo ${d-$X}
если макропеременная d определена, выдаст ее значение, если
нет - значение макропеременной X.
Значение по умолчанию макропеременной может быть опре-
делено следующим образом:
- 29 -
echo ${d=.}
если макропеременная d не определена, ей присваивается сим-
вол '.' (для позиционных параметров обозначение ${...=...}
использовать нельзя).
Команда
echo ${d?сообщение}
выдает значение макропеременной d, если оно определено, и
сообщение - если не определено. В последнем случае выполне-
ние командного файла завершается. Если сообщение отсутст-
вует, то выдается стандартная диагностика интерпретатора.
Командный файл, часть параметров которого должна иметь опре-
деленные значения, может начинаться следующим образом:
: ${USER?} ${HOME?} ${BIN?}
...
Двоеточие : представляет собой встроенную команду языка
SHELL, предназначенную для оценки значений своих параметров.
Если значение хотя бы одной из переменных USER, HOME или BIN
не определено, выдается диагностика и выполнение командного
файла прекращается.
4.3. Подстановка результатов выполнения команд
В языке SHELL существует возможность использования
результата выполнения команд в различных целях. Так, стан-
дартным выходом команды pwd является имя текущего справоч-
ника, и если таким справочником является, например,
/usr/nata/bin, то команда
d=`pwd`
будет эквивалентна команде
d=/usr/nata/bin
Строка, заключенная между обратными кавычками `...`, воспри-
нимается как команда и заменяется результатом выполнения
этой команды. Команды записываются с использованием обычных
соглашений об отмене специальных значений метасимволов, за
исключением того, что специальное значение символа обратной
кавычки "`" отменяется символом \. Например, команда
ls `echo $1`
эквивалентна команде
ls $1
- 30 -
Везде, где разрешена подстановка значений параметров,
может производиться и подстановка результатов выполнения
команд (в том числе и в локальных файлах). Обработка резуль-
татов в обоих случаях выполняется одинаково. Это позволяет
использовать в процедурах языка SHELL команды, предназначен-
ные для обработки строк. Примером такой команды является
команда basename, которая удаляет из слова указанный суф-
фикс. Например, в результате выполнения команды
basename main.c .c
будет получена последовательность символов main. Использова-
ние команды basename можно проиллюстрировать следующим фраг-
ментом команды cc:
case $A in
...
*.c) B=`basename $A .c`
...
esac
В этом примере макропеременной B присваивается значение мак-
ропеременной A, из которой удален суффикс .c.
4.4. Обработка ошибок
Действия интерпретатора при обнаружении ошибки зависят
от двух обстоятельств: типа ошибки и режима работы интерпре-
татора. Режим работы интерпретатора считается интерактивным
в том случае, если ввод/вывод информации осуществляется с
терминала или интерпретатор вызван с ключом -i.
Приведем список причин, которые приводят к ошибкам при
выполнении команды:
- неверное указание файлов ввода/вывода (например, файл
не существует или не может быть создан);
- самой команды не существует, или она не может быть
выполнена;
- команда вызвалась нормально, но ее код завершения
имеет ненулевое значение.
Если интерпретатор работает в интерактивном режиме, то,
независимо от результата завершения предыдущей команды, он
переходит к выполнению следующей.
В не интерактивном режиме два вида ошибок приводят к
прекращению обработки командного файла:
- синтаксическая ошибка в операторах управления (while,
until, if, for);
- 31 -
- ошибка при выполнении встроенной команды.
Для того чтобы обеспечить прекращение выполнения
команды при обнаружении любой из указанных ошибок, при
вызове интерпретатора необходимо использовать ключ -e.
4.5. Обработка прерываний