Андрей Робачевский - Операционная система UNIX
В этом разделе приведены сведения о языке Bourne shell, достаточные, чтобы разобраться в системных скриптах и написать простейшие скрипты. Данное описание ни в коем случае не претендует на полное руководство по программированию на языке командного интерпретатора.
Общий синтаксис скрипта
Как уже было замечено, скрипт представляет собой обычный текстовый файл, в котором записаны инструкции, понятные командному интерпретатору. Это могут быть команды, выражения shell или функции. Командный интерпретатор считывает эти инструкции из файла и последовательно выполняет их.
Безусловно, как и в случае любого другого языка программирования, применение комментариев существенно облегчает последующее использование и модификацию написанной программы. В Bourne shell комментарии начинаются с символа '#':
# Этот скрипт выполняет поиск "мусора" (забытых временных
# файлов, файлов core и т.п.) в каталогах пользователей
Комментарии могут занимать не всю строку, а следовать после команды:
find /home -name core -print # Выполним поиск файлов core
Поскольку в системе могут существовать скрипты для различных интерпретаторов, имя интерпретирующей команды обычно помещается в первой строке следующим образом:
#!/bin/sh
В данном случае последующий текст скрипта будет интерпретироваться Bourne shell. Заметим, что при запуске скрипта из командной строки (для этого он должен обладать правом на выполнение — x), будет запущен новый командный интерпретатор, ввод команд для которого будет выполняться из файла скрипта.
Переменные
В командной строке или скрипте командного интерпретатора можно определить и использовать переменные. Значением переменной является строка, которая передается присвоением:
var=value
где var — имя переменной, a value — ее значение.
Значение переменной можно получить, используя знак. Например, вывести значение переменной name на экран можно с помощью команды echo следующим образом:
$ echo $name
Так же можно присвоить другой переменной (name1) значение переменной name:
$ name1=$name
Значение переменной можно присвоить иначе. Поскольку значение представляет собой строку, shell предоставляет удобный способ генерации строк из потока вывода команды. Синтаксис присвоения при этом следующий:
var=`command`
Так, например, где var — имя переменной, a command — название команды, команда pwd(1) выводит строку со значением текущего каталога:
$ pwd
/usr/home/andrei/test
Можно присвоить переменной cdir значение текущего каталога, которое сохранится в ней:
$ cdir=`pwd`
$ echo $cdir
/usr/home/andrei/test
$ cd /usr/bin
$ pwd
/usr/bin
$ cd $cdir
$ pwd
/usr/home/andrei/test
При использовании переменной, например var, командный интерпретатор подставляет вместо $var ее значение. Более сложные синтаксические конструкции получения значения переменной приведены в табл. 1.7.
Таблица 1.7. Способы получения значения переменной
$var Значение var; ничего, если переменная var не определена ${var} То же, но отделяет имя переменной var от последующих символов ${var:-string} Значение var, если определено; в противном случае — string. Значение var при этом не изменяется ${var:=string} То же, но если переменная var не определена, ей присваивается значение строки string ${var:?string} Если переменная var не определена, выводится строка string и интерпретатор прекращает работу. Если строка string пуста, то выводится сообщение var: parameter not set ${var:+string} Строка string, если переменная var определена, в противном случае — ничегоПриведем несколько примеров, используя команду echo:
$ var=user1
$ var1=user2
$ echo $var1
user2
$ echo ${var}l
user11
$ echo ${var1:+"do you want to redefine var?"}
do you want to redefine var?
Для нормальной работы в UNIX ряд переменных должен быть определен и зависит от тех приложений, с которыми вы работаете. Приведем несколько наиболее употребительных переменных:
Имя Описание Возможное значение НОМЕ Каталог верхнего уровня пользователя /usr/'logname'[13] PATH Поисковый путь /bin:/etc:/usr/bin:. MAIL Имя почтового ящика /usr/spool/mail/'logname' TERM Имя терминала ansi PS1 Первичное приглашение shell # PS2 Вторичное приглашение shell >Начальное окружение вашего сеанса устанавливается программой login(1) исходя из записей в файле паролей, и имеет следующий вид:
Переменная окружения Поле файла паролей HOME=домашний_каталог 6 LOGNAME=зарегистрированное_имя 1 PATH=/usr/bin: - SHELL=интерпретатор_сеанса 7 MAIL=/var/mail/зарегистрированное_имя 1 TZ=временная_зона определено системойПеременная НОМЕ в основном используется в команде cd, которая служит для перехода в каталог:
$ pwd
/u/usr
$ cd some/new/directory
$ pwd
/u/usr/some/new/directorу
В результате текущим каталогом (команда pwd(1) выводит на терминал полное имя текущего каталога) становится /u/usr/some/new/directory. Вызов команды cd без параметра эквивалентен следующему вызову:
$ cd $HOME
который вернет вас в домашний каталог.
Переменная PATH служит для поиска командным интерпретатором запускаемых на выполнение программ, если их имя не содержит пути. Например, при запуске программы:
$ run
интерпретатор попытается найти файл run в каталогах пути поиска. В то же время при запуске программы run с указанием пути, переменная PATH использоваться не будет:
$ ./run
В последнем примере было задано относительное имя программы (относительно текущего каталога, обозначаемого точкой). Предполагается, что файл программы имеется в текущем каталоге, в противном случае shell выведет сообщение об ошибке.
Каталоги поиска в переменной PATH разделены символом ':'. Заметим, что текущий каталог поиска должен быть задан явно ('.'), shell не производит поиск в текущем каталоге по умолчанию.
Поиск запускаемых программ в текущем каталоге таит потенциальную опасность, поэтому для суперпользователя переменная PATH обычно инициализируется без '.'. Рассмотрим следующую ситуацию. Злоумышленник создает программу, наносящую вред системе (удаляющую файл паролей), помещает ее в каталог общего пользования, например в /tmp, открытый на запись всем пользователям системы, с именем ls. Известно, что в UNIX существует стандартная команда ls(1) (она обычно находится в каталоге /bin), выводящая на экран список файлов каталога. Допустим теперь, что администратор системы делает текущим каталог /tmp и хочет вывести список файлов данного каталога. Если текущий каталог ('.') расположен в пути поиска (переменной PATH) раньше каталога /bin, то выполнится программа, "подложенная" злоумышленником. Даже если текущий каталог указан последним в пути поиска, все равно существует вероятность, что вы захотите запустить команду, которая расположена в каталоге, не попавшем в переменную PATH, на самом деле вы можете запустить троянского коня.