Рассылка закрыта
При закрытии подписчики были переданы в рассылку "Интернет: маркетинг, реклама, торговля" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
Страницы справочного руководства ОС UNIX на русском : Основы ОС UNIX (10)
Информационный Канал Subscribe.Ru |
Выпуск 120
Уважаемые подписчики!
Сегодня вашему вниманию предлагается десятая часть курса, посвященная
управляющим конструкциям командных интерпретаторов (sh, ksh, bash) ОС UNIX.
Ваши отзывы об этих учебных материалах шлите мне по почте, в гостевую или оставляйте в комментариях на соответствующей странице проекта "Хроника бегства от безопасности".
Основы ОС UNIX. Учебный курс. Часть 10
Copyleft (no c) - Fuck copyright! 1996-2003 В. Кравчук, OpenXS Initiative, идея, составление, перевод, примеры
Циклы в командном интерпретаторе
Командный интерпретатор поддерживает циклическую обработку. Чаще всего на практике используется цикл for - цикл по списку слов. Он описан в следующем подразделе.
Обратите внимание, что выделенные полужирным ключевые слова должны быть первым словом команды, т.е. первым словом в строке или идти сразу после точки с запятой.
Цикл for
Цикл for имеет следующий синтаксис:
- <цикл for> ::=
- for <имя переменной> [in <список слов>] do <команды> done
- <список слов> ::=
- <слово>{<пробел> <слово>}
- <команды> ::=
- <команда> {<; или перевод строки> <команда>}
Переменная последовательно получает значение очередного слова из списка, и для этого значения выполняются команды в теле цикла. Цикл завершается, когда пройден весь список слов. По умолчанию в качестве списка слов используются аргументы командной строки.
Рассмотрим пару примеров таких циклов:
$ for i in 1 2 3 4 5 > do > echo $i > done
Обратите внимание, что командный интерпретатор распознает цикл, выдает вторичное приглашение, и выполняет цикл только после его завершения ключевым словом done.
Список слов для цикла обычно порождается динамически. Например, путем раскрытия шаблонов имен файлов:
$ for i in *.c *.h > do > echo $i > diff -b old/$i $i > echo > done | pr -h "diff `pwd`/old `pwd`" | lp & [4] 1430
Можно также порождать его командой, подставляя ее результаты:
$ for i in `pick *.c *.h` > do > echo $i: > diff -b old/$i $i > done | pr | lp
Операторы цикла while и until
Командный интерпретатор поддерживает также традиционные циклы по условию со следующим синтаксисом:
- <оператор while> ::=
- while <команды> do <команды> done
- <оператор until> ::=
- until <команды> do <команды> done
Выполняются команды, задающие условие, и проверяется код возврата последней из них. Если это ноль (истина), выполняются команды в теле цикла while или завершается выполнение цикла until. Если это не ноль (ложь), завершается работа цикла while или выполняется очередная итерация цикла until.
На основе этих циклов часто создаются программы-"следилки", работающие бесконечно:
$ cat watchfor # watchfor: watching for log ins and log outs... PATH=/usr/bin new=/tmp/wfor1.$$ old=/tmp/wfor2.$$ >$old # создает пустой файл while : # бесконечный цикл do who >$new diff $old $new mv $new $old sleep 60 done | awk ' />/ { $1 = "in: "; print } /</ { $1 = "out: "; print }' $
Оператор выбора
Командный интерпретатор поддерживает выполнение того или иного блока команд в зависимости от значения некоторого слова. Для этого предлагается оператор case со следующим синтаксисом:
- <оператор выбора> ::=
- case <слово> in
<описание варианта> ) <команды> ;;
{<описание варианта> ) <команды> ;; }
esac - <описание варианта> ::=
- <шаблон> { | <шаблон>}
- <команды> ::=
- <команда> {<разделитель> <команда>}
- <разделитель> ::=
- <перевод строки> | ;
Слово (обычно - значение переменной) сравнивается последовательно с шаблонами. Если произошло сопоставление (по правилам сопоставления шаблонов имен файлов) выполняются команды, соответствующие данному варианту и оператор завершается. Учтите, что шаблон *) сопоставляется с любым словом, и, тем самым, задает вариант по умолчанию.
В шаблонах оператора case символы . и /, в отличие от шаблонов имен файлов, не обязательно задавать явно.
Условный оператор
Командный интерпретатор поддерживает условный оператор следующего общего вида:
- <условный оператор> ::=
- if <команды> then <команды>
{elif <команды> then <команды>}
[else <команды>]
fi
Выполняются команды после if и проверяется код возврата последней из них. Если это 0 (истина) выполняются соответствующие команды после then и выполнение оператора завершается. Если же это не 0 (ложь), то при наличии конструкций elif выполняются последовательно соответствующие команды-условия и, если они возвращают код 0, команды после then, а затем оператор завершается. Если ни одно из условий не было истинным, выполняются команды в части else и оператор завершается.
В качестве условия в условном операторе может использоваться любая команда. Однако, имеется стандартная команда для проверки условий в традиционном понимании. Это команда test, представленная в следующем разделе.
Проверка условий в командном интерпретаторе
Команда test имеет следующий синтаксис:
- <команда test> ::=
- test <выражение> | [ <выражение> ]
Выражение строится из примитивов, представленных в табл. 26, при необходимости, с помощью следующих операторов:
! | Унарный оператор отрицания. |
-a | Бинарный оператор "и". |
-o | Бинарный оператор "или". |
(<выражение>) | Скобки для группировки. Учтите, что скобки распознаются командным интерпретатором, поэтому их надо брать в кавычки. |
Таблица 26. Основные примитивы команды test
Примитив | Условие |
-r файл | файл существует и доступен для чтения |
-w файл | файл существует и доступен для записи |
-x файл | файл существует и является выполняемым |
-f файл | истина, если файл существует и является обычным файлом (не каталогом) |
-d файл | файл существует и является каталогом |
-h файл | файл существует и является символьной связью |
-s файл | файл существует и не пуст |
-t [ дескриптор ] | истина, если открытый файл с указанным дескриптором (по умолчанию, 1) ассоциирован с терминалом |
-z s1 | истина, если строка s1 имеет нулевую длину |
-n s1 | истина, если строка s1 имеет ненулевую длину |
s1 = s2 | истина, если строки s1 и s2 идентичны |
s1 != s2 | истина, если строки s1 и s2 не совпадают |
s1 | истина, если строка s1 непустая |
n1 -eq n2 | сравнение целых чисел на равенство (=). Можно использовать также и другие сравнения: -ne (!=), -gt (>), -ge (>=), -lt (<) и -le (<=). |
Рассмотрим пример использования условного оператора и команды test:
$ cat which # which cmd: Безопасная версия сценария для выдачи каталога, # из которого будет вызываться выполняемая программа opath=$PATH PATH=/usr/bin # Это гарантирует использование настоящих команд # echo, sed и test в любом случае! case $# in 0) echo 'Usage: which command' 1>&2; exit 2 esac for i in `echo $opath | sed 's/^:/.:/ s/::/:.:/g s/:$/:./ s/:/ /g'` do if test -x $i/$1 then echo $i/$1 exit 0 # команда найдена fi done exit 1 # не найдена $ which sed ./sed $ which which ./which
Перехват и обработка сигналов
В программах командного интерпретатора можно перехватывать и обрабатывать сигналы. Для этого используется команда trap, устанавливающая с момента выполнения обработчик в виде последовательности команд (одним словом) для всех перечисленных сигналов. Эта команда имеет следующий синтаксис:
- <оператор trap> ::=
- trap <последовательность команд> <список сигналов>
- <список сигналов> ::=
- <сигнал> {<пробелы> <сигнал>}
Рассмотрим пример реализации команды nohup, позволяющей запустить программу так, чтобы она продолжала работать при выключении терминала:
$ cat nohup # nohup: no kill and hangup trap "" 1 15 if test -t 2>&1 then echo "Redirect stdout to 'nohup.out'" exec nice -5 $* >>nohup.out 2>&1 else exec nice -5 $* 2>&1 fi $
Запрос информации у пользователя
Командный интерпретатор позволяет, при необходимости, запрашивать у пользователя информацию, которая помещается в указанную переменную. Для этого используется команда read:
$ read greeting Hello, world! $ echo $greeting Hello, world! $
На практике имеет смысл перед запросом выдать приглашение с помощью команды echo. Например, вот так:
$ cat pick # pick: select arguments PATH=/bin:/usr/bin for i # for each argument, try $*, "$*" and "$@" do echo -n "$i? " > /dev/tty read responce case $responce in y*) echo $i;; q*) break esac done </dev/tty $
Представленная выше программа pick выдает каждое указанное в качестве аргумента слово в отельной строке со знаком вопроса и требует от пользователя подтвердить необходимость его выдачи в стандартный выходной поток. Поскольку эта программа может использоваться в других сценариях, входной и выходной потоки которых перенаправлены, она взаимодействует непосредственно с текущим терминалом (через устройство /dev/tty).
Вычисления в командном интерпретаторе
Вычисления можно выполнять с помощью любой программы, воспринимающей свои параметры как выражение, значение которого необходимо вычислить, и выдающей результат вычисления в стандартный выходной поток. Одна из таких программ, expr, рассмотрена далее. Но современные командные интерпретаторы включают встроенную команду для выполнения простейших арифметических действий. Это команда let:
- <команда let> ::=
- let <аргумент> {<аргумент>}
Вот как ее можно использовать:
$ let a=5 $ echo $a 5 $ let a=a*a+34/2 $ echo $a 42 $ let "a = 7" $ echo $a 7
Обратите внимание, что если вокруг знака равенства идут пробелы, необходимо брать выражение в кавычки. Команда let требует, чтобы выражение было одним словом. Кроме того, для обращения к значению переменной в этой команде не нужно использовать метасимвол $.
Команда expr
Одной из стандартных программ-калькуляторов является программа expr. Ее основные операторы представлены в табл. 27.
Таблица 27. Основные операторы, распознаваемые командой expr
Оператор | Результат |
выр1 \| выр2 | Возвращает значение первого выражения, если оно не пустое и не равно 0, иначе, возвращает значение второго выражения. |
выр1 \& выр2 | Возвращает значение первого выражения, если оба выражения - не пустые и не равны 0, иначе, возвращает 0. |
выр1 { +, - } выр2 | Складывает или вычитает целочисленные аргументы. |
выр1 { \*, /, % } выр2 | Умножает, делит или возвращает остаток от деления для целочисленных аргументов. |
length строка | Возвращает длину строки. |
Рассмотрим простой пример вычисления с помощью expr:
$ a=5 $ echo $a 5 $ a=`expr $a \* $a + 34 / 2` $ echo $a 42
Обратите внимание, что между элементами выражения надо указывать пробелы.
Функции в командном интерпретаторе
Стандартным способом разбиения программ на модули в командном интерпретаторе является оформление необходимых действий в виде отдельного выполняемого файла с программой командного интерпретатора - создание новой команды. Тем не менее, для некоторых модулей такой подход может оказаться неэффективным и избыточным, так как модули могут не представлять самостоятельного значения вне программы, в которой они используются. Поэтому в современных версиях командных интерпретаторов предлагается возможность создавать и вызывать функции.
Синтаксис определения функции
Для определения функций используется ключевое слово function. Функции читаются и хранятся внутренне командным интерпретатором. Функции выполняются как команды, причем аргументы передаются как позиционные параметры. Синтаксис определения функции следующий:
- <определение функции> ::=
- function <идентификатор> { <список команд> } |
<идентификатор> () { <список команд> }
где список команд задает команды, выполняемые в качестве тела функции. Команды обычно разделяются точкой с запятой или переводами строк.
Выполнение и использование функций
Функции выполняются вызвавшим их процессом и используют все его файлы и текущий рабочий каталог. Сигналы, перехватываемые вызывающим процессом, внутри фунции обрабатываются стандартным образом. Сигналы, не перехватываемые или игнорируемые функцией, прекращают ее выполнение и передаются вызвавшей команде.
Обычно переменные совместно используются вызывающей программой и функцией. Однако, специальная команда typeset, используемая внутри функции, позволяет определять локальные переменные, область действия которых - текущая функция и все вызываемые ею функции.
Для выхода из функции используется специальная команда return. В случае ошибки в функции, управление передается вызывающей команде.
Идентификаторы определенных функций можно получить с помощью опций -f или +f специальной команды typeset. Текст функций показывается при использовании опции -f. Определение функции можно отменить с помощью опции -f специальной команды unset.
Обычно при выполнении сценария командным интерпретатором никакие функции не заданы. Опция -xf команды typeset позволяет экспортировать функцию для использования сценариями, выполняемыми без отдельного вызова интерпретатора. Функции, которые должны быть определены для всех вызовов интерпретатора, необходимо задавать в файле начального запуска с помощью опций -xf команды typeset.
Рассмотрим классический пример итеративной реализации функции вычисления факториала:
# test.sh - test shell functions factorial () { typeset i typeset n i=1; n=1 while [ $i -le $1 ] do let n=n*i let i=i+1 done echo $n return } a=`factorial $11` echo $a
При вызове эта программа, как и ожидалось, вычислит факториал своего первого параметра:
bash$ test.sh 5 120
Часто в виде функций оформляется выдача сообщений о параметрах вызова программы. В любом случае, если задача может быть разбита на подзадачи, решение этих подзадач имеет смысл оформлять в виде отдельной команды, если они полезны не только в контексте решаемой задачи, или в виде функции в противном случае.
Файлы начального запуска командного интерпретатора
Стандартная среда для работы командных интерпретаторов задается в файлах начального запуска, которые автоматически выполняются в начальном интерпретаторе с помощью команды точка (.), т.е. без порождения. Файлы начального запуска размещаются в начальном каталоге пользователя и называются .profile (sh, ksh) или .bash_profile (bash). Переменные, составляющие среду, в файле начального запуска надо экспортировать.
Рассмотрим пример содержимого файла начального запуска:
INFORMIXDIR=/usr/inf.731 INFORMIXSERVER=onarturo7 ONCONFIG=onconfig SQLHOSTS=sqlhosts PATH=$PATH:$INFORMIXDIR/bin LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$INFORMIXDIR/lib/esql:$INFORMIXDIR/lib DB_LOCALE=ru_ru.8859-5 CLIENT_LOCALE=ru_ru.8859-5 KAIOON=1 NODEFDAC=YES DBDATE=DMY4/ DBTIME='%H:%M:%S %d/%m/%Y' DBMONEY=.4 export KAIOON export INFORMIXDIR INFORMIXSERVER LANG PATH ONCONFIG SQLHOSTS export DBDATE DBTIME DBMONEY NODEFDAC export DB_LOCALE CLIENT_LOCALE
В следующем выпуске
Последняя часть учебного курса "Основы ОС UNIX". Следите за новостями на сайте рассылки.С наилучшими пожеланиями,
В.К.
http://subscribe.ru/
E-mail: ask@subscribe.ru |
Отписаться
Убрать рекламу |
В избранное | ||