Документация по ОС FreeBSD Вторник, 17.06.2025, 06:08
Приветствую Вас Гость | RSS
Меню сайта

Категории каталога
Мои статьи [0]
Установка и настройка [281]
X Window [25]
Man pages [30]
Ports & Packages [26]
cvs [18]
Multimedia [20]
Нововсти в мире Unix [0]
RFC [4]
RFC (Request for Comments, Запрос на комментарии) - серия документов, публикуемая сообществом исследователей и разработчиков, руководствующихся практическими интересами, в которой описывается набор протоколов и обобщается опыт функционирования Интернет.
Безопасность [52]
Работа с железом [58]
Книги по FreeBSD [17]
Сеть [505]
Программирование [40]
FireWall [58]
Темы экзамена BSDA [14]
Официальные темы экзамена BSDA, включая подробноые описания и советы по обучению.

Главная » Статьи » Установка и настройка

Основы ОС 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 }
 /

Оператор выбора

Командный интерпретатор поддерживает выполнение того или иного блока команд в зависимости от значения некоторого слова. Для этого предлагается оператор 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 

Представленная выше программа 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
Категория: Установка и настройка | Добавил: oleg (10.12.2007)
Просмотров: 958 | Рейтинг: 0.0/0 |
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Форма входа

Beastie

Друзья сайта

Статистика

Онлайн всего: 3
Гостей: 3
Пользователей: 0
links

Copyright MyCorp © 2025