<< Предыдущий раздел | /\ Содержание | >> Следующий раздел

Что такое скрипты, зачем они нужны и как их делать

Что такое скрипт


Скрипт -- это программа на языке shell. Вместо термина скрипт иногда используется термин сценарий.

Скрипт в Unix -- это практически то же самое, что командный файл в Dos (.bat-файлы) и VMS (.com-файлы). Отличие в том, что, поскольку скрипты являются обычными программами, то вызываются они просто по имени (а не специальной командой типа "call" или "@"), могут иметь произвольное имя (специальное расширение типа .bat не нужно), и нет ограничений на глубину вызовов скриптов из других скриптов.

Простейший скрипт -- это несколько обычных команд shell, которые должны выполняться последовательно.

При обычной работе в командной строке shell зачастую приходится писать довольно длинные команды, постоянно набирать которые заново в конце концов попросту надоедает (да и вероятность допустить опечатку тем выше, чем длиннее команда). Некоторые последовательности команд приходится повторять также все снова и снова. Вот такие команды и их последовательности и являются хорошими кандидатами для помещения в скрипты, чтобы потом их можно было вызвать по короткому имени.

Язык shell, однако, довольно мощный -- он позволяет работать с переменными, содержит конструкции типа "while", "for", "if-then-else", функции и другие атрибуты, присущие языкам структурного программирования. Это позволяет выполнять на shell достаточно сложные действия. Многие программы в Unix являются именно скриптами -- например, startx и больщинство программ, выполняющих инициализацию/останов системы (они расположены в /etc/rc.d/).

Хотя термин "скрипт" обычно подразумевает сценарий на языке shell, в Unix есть и другие скрипт-языки, зачастую специализированные. Все они объединяются тем, что являются интерпретаторами -- т.е. программа является текстовым файлом, который исполняется сразу же, не требуя предварительной компиляции в бинарный файл.

В многообразном мире Unix у такого подхода есть большое достоинство: один и тот же скрипт может без всяких изменений использоваться в разных видах Unix (в том числе и браться ими непосредственно из одного файла -- например, по NFS).

Как сделать скрипт


Как говорилось выше, простейший скрипт -- это несколько команд shell, записанных в файл. Создавать файлы скриптов удобнее всего в текстовом редакторе, но можно и при помощи команды "cat >файл" -- при этом cat принимает ввод с клавиатуры до нажатия <Ctrl+D>.

Чтобы дать понять системе, что это исполняемый файл (программа), надо установить для него атрибут "x".

Пример: создание скрипта, содержащего команду "ls -l | less":

bobby:~% cat >lls
ls -l | less
<Ctrl+D>
bobby:~% ls -l lls
-rw-r--r--   1 ivanov   lab5           13 May 14 17:36 lls
bobby:~% chmod +x lls
bobby:~% ls -l lls
-rwxr-xr-x   1 ivanov   lab5           13 May 14 17:36 lls
bobby:~% _

Запустить затем этот скрипт можно, набрав "./lls".

Но, находясь в другой директории, придется вызывать этот скрипт по полному имени (например, "~/lls"), что довольно неудобно. Поэтому следует поместить такую "свежесделанную" программу в одну из директорий, перечисленных в переменной окружения PATH.

Чтобы у каждого пользователя была возможность создавать и удобно запускать свои программы, в переменной PATH всегда присутствует ссылка на поддиректорию bin/ в home-директории пользователя:

bobby:~% echo $PATH
/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/users/ivanov/bin
bobby:~% _

Если в home-директории bin/ отсутствует, то ее надо просто создать командой "mkdir ~/bin".

Скрипты (как, впрочем, и любые другие программы), расположенные в ~/bin/, вызываются просто по имени:

bobby:~% lls
zsh: command not found: lls
bobby:~% mkdir bin
bobby:~% mv lls bin/
bobby:~% lls
...Запускается скрипт lls...

Если в первой строчке скрипта стоит "#!/bin/sh"...


Поскольку скрипты написаны на языке shell, то они должны исполняться (интерпретироваться) какой-то программой. По умолчанию в качестве интерпретатора система использует /bin/sh.

Но можно явно указать интерпретатор, если в начале самой первой строки файла поставить символы "#!" ("решетка" и восклицательный знак), а затем -- полный путь к программе-интерпретатору. Например, чтобы воспользоваться в скрипте дополнительными возможностями, предоставляемыми zsh по сравнению с sh, надо поставить первой строкой

#!/bin/zsh

Таким образом, при отсутствии "#!" система ведет себя так, как если бы там стояло "#!/bin/sh". Вообще говоря, хорошим тоном считается в обычных shell-скриптах ставить эту строку, хотя она и не обязательна -- тогда по файлу сразу ясно, что он является shell-скриптом.

В скриптах на других языках в первой строке обязательно указывается программа-интерпретатор -- например, для Perl -- "#!/usr/bin/perl".

Скрипты с параметрами


Поскольку обычные программы могут вызываться с некоторыми параметрами (например, "ls /etc"), то рано или поздно такая же необходимость возникает и в скриптах.

Для подстановки значения первого указанного параметра используется название "$1", второго -- "$2" и т.д. -- аналогично массиву "argv[]" в программах на языке C. Таким образом, если переделать наш скрипт lls из

ls -l | less
в

ls -l $1| less
то он будет показывать при помощи less длинный листинг не текущей, а указанной директории. Если при вызове lls не будет указана никакая директория, то "$1" будет равен "ничему" (пустой строке), и в результате получится команда "ls -l | less" -- та же, что и раньше.

Специальное название "$*" означает "все параметры". Таким образом, если переделать наш скрипт в

ls -l $* | less
то, к примеру, команда

lls /bin /usr/bin /usr/local/bin
будет воспринята как

ls -l /bin /usr/bin /usr/local/bin | less

Использование переменных


Как известно из теории программирования, практически любая программа рано или поздно потребует для гибкости использования переменных.

Переменные в языке shell -- это почти то же самое, что переменные окружения. В отличие от таких языков, как C или Pascal, все переменные в shell -- строковые (а не числовые).

Для присвоения переменной значения служит конструкция вида

ИМЯ=значение
(вокруг "=" не должно быть пробелов!).

Если присваиваемое переменной значение содержит пробелы или какие-либо символы, имеющие специальный смысл для shell (*, <, >, & и т.д.), то значение надо заключить в кавычки.

Для получения значения переменной используется конструкция $ИМЯ (в отличие от Makefile, скобки вокруг имени указывать не следует).

Заметьте, что это очень похоже на использование параметров $1, $2 и т.д. -- для shell они являются псевдопеременными ("псевдо" потому, что значения их изменять нельзя).

Таким образом, и использованием переменных наш скрипт можно переписать следующим образом:

LS="ls -l"
VIEWER=less

$LS $* | $VIEWER

(Конечно, не самый осмысленный пример, но весьма наглядный.)

Другие скрипт-языки


Кроме shell, в Unix существует еще довольно много языков для скриптов. В таблице ниже приведены наиболее распространенные и частоиспользуемые из них.

Какие бывают script-языки и зачем они нужны
ПрограммаЯзыкПрименение
/bin/shShellОсновной язык системы, в т.ч. initscripts
/usr/bin/perlPerlЯзык, похожий по синтаксису на C, для создания мощных скриптов, со сложными структурами данных
/bin/awkawkМощнее shell, но проще perl
/bin/sedsed"Stream editor" -- Скорее не язык, а фильтр
/usr/bin/tclshTcl"Tool Command Language" -- язык для написания простых приложений
/usr/bin/wishTcl/TkЯзык на основе Tcl для программ с оконным интерфейсом
/usr/bin/expectExpectЯзык для мультизадачных сценариев

Замечание
В данной таблице перечислены стандартные пути к интерпретаторам, но в некоторых дистрибутивах они могут и отличаться.

Где можно почитать про создание shell-скриптов


Хорошим пособием является книги Б.Керниган, Р.Пайк "UNIX - универсальная среда программирования", главы 3-5, и У.Дэвис "Операционные системы", М., Мир, 1986.

В качестве справочника по конструкциям языка shell стоит использовать man-страницу на sh или bash (собственно, именно bash "работает" в Linux в качестве sh, в этом легко убедиться при помощи команды "ls -l /bin/sh").

Псевдонимы (aliases)

Для простых частоиспользуемых команд необязательно создавать скрипт -- достаточно сделать "псевдоним" (alias).

Shell всегда проверяет самое первое слово каждой команды (т.е. собственно имя команды), не является ли оно псевдонимом, и если да, то заменяет его "значением" псевдонима.

К примеру, если сделать "ll" псевдонимом для "ls -l", то команда

ll /etc
будет исполняться как

ls -l /etc

Для определения псевдонимов используется оператор alias. Пример:

alias ll='ls -l'
Аналогично определению переменных, вокруг символа "=" не должно быть пробелов, а если в "значении" псевдонима есть пробелы или спецсимволы, то его следует "закавычить".

Посмотреть список псевдонимов можно командой alias без параметров:

bobby:~% alias
ls='/bin/ls --color=tty -F -T 0'
run-help=man
which-command=whence
bobby:~% _

"Разопределить" псевдоним можно командой unalias:

bobby:~% alias
ls='ls --color=tty -F -T 0'
run-help=man
which-command=whence
bobby:~% alias ll='ls -l'
bobby:~% alias
ll='ls -l'
ls='ls --color=tty -F -T 0'
run-help=man
which-command=whence
bobby:~% unalias ll
bobby:~% alias
ls='/bin/ls --color=tty -F -T 0'
run-help=man
which-command=whence
bobby:~% _

У псевдонимов есть две уникальных особенности. Во-первых, shell проверяет, не псевдоним ли это, до того, как начнет искать команду с таким именем. Во-вторых, после "подстановки" значения псевдонима первое слово получившейся команды опять проверяется на предмет того, не является ли оно псевдонимом, но "уже найденные" псевдонимы при этом не учитываются.

Таким образом, можно определить псевдоним с именем уже существующей команды, слегка модифицировав ее поведение или даже полностью заменив ее. В приведенном выше примере команда ls модифицирована так, чтобы всегда автоматически указывались коючи "--color=tty", "-F" и "-T 0".

Поскольку значения псевдонимов также проверяются на псевдонимы, то в приведенном примере при использовании псевдонима ll команде ls будут указываться дополнительные ключи.


"Вручную" псевдонимы практически никогда не делаются, а их определения обычно помещаются в стартовые файлы shell, аналогично определениям переменных окружения.

Единственное, чего псевдонимы не умеют -- так это "работать" в качестве скриптов с параметрами. Но для этого служат функции.

Функции (functions)

Функция в shell, как и в обычных языках программирования -- это небольшой фрагмент кода, выполняющий некое логически законченное действие, и, возможно, вызываемый из основной программы несколько раз.

Функция -- это как бы скрипт внутри скрипта.

Синтаксис определения функции следующий:

function ИМЯ_ФУНКЦИИ () {
  команды тела функции
}

Внутри функции имена "$1", "$2" и т.д. содержат параметры, указанные в вызове функции, аналогично тому, как обычно они содержат параметры, указанные скрипту (которые, в свою очередь, изнутри функции недоступны).

Например, переписать наш скрипт lls в виде функции можно следующим образом:

function lls () {
  ls -l $* | less
}

Посмотреть список функций можно командой "typeset -f", а "разопределить" функцию -- командой "unset -f":

bobby:~% typeset -f
lls () {
        ls --color=tty -F -T 0 -l $* | less
}
setenv () {
        export $1=$2
}
bobby:~% unset -f lls
bobby:~% typeset -f
setenv () {
        export $1=$2
}
bobby:~% _

Функции удобно применять в скриптах, а псевдонимы -- в интерактивной работе (т.е. для команд, вводимых непосредственно в командной строке).

Замечание
В zsh (но не в скриптах!) вместо "typeset -f" для просмотра списка функций можно использовать команду functions, а для "разопределения" вместо "unset -f" -- команду unfunction.

В определении функций ключевое слово "function" необязательно, и его можно просто опускать.

В оболочках csh/tcsh функции не поддерживаются.


<< Предыдущий раздел | /\ Содержание | >> Следующий раздел