Linux и UNIX: программирование в shell. Руководство разработчика.

Тейнсли Дэвид

Часть 5

 

 

Совершенствование навыков по написанию сценариев

 

ГЛАВА 25

 

Дальнейшее изучение конструкции "документ здесь"

При рассмотрении стандартного потока ввода и вывода, а также циклов while уже обсуждалась конструкция "документ здесь". Описывались методика пересылки электронной почты и способы формирования экранов меню, но существуют и другие способы применения конструкции "документ здесь".

В этой главе рассматриваются следующие темы:

   • скоростной метод создания файла;

   • меню с автоматизированными возможностями поиска;

   • передача файлов с помощью протокола ftp;

   • подключение к другим системам приложений.

Формат конструкции "документ здесь":

команда << слово

текст

слово

Чтобы вспомнить методы применения конструкции "документ здесь", рассмотрим принципы ее работы. Когда интерпретатор shell встречает символ <<, он ожидает встретить за ним разделитель (слово). Все, что следует за этим словом до следующего слова в строке, воспринимается как поток ввода. В качестве разделителя может служить любое слово.

Конструкция "документ здесь" может применяться при создании файла, выводе на экран списка файлов, сортировке списка файлов и при создании экранов.

 

25.1 Быстрый метод формирования файла

Ниже рассматривается быстрый метод формирования файла, содержащего некоторый текст:

$ cat >> myfile << NEWFILE

Введите какой‑нибудь текст, а по завершении ввода в новой строке просто укажите слово NEWFILE. В результате образуется файл myfile, содержащий этот текст.

Если файл с указанным именем существует, то вводимое содержимое добавляется в исходный файл.

При использовании клавиши [Tab] следует учитывать, что более ранние версии

командного интерпретатора не сохраняют значения символов табуляции. Для устранения этого недостатка введите дефис после двух угловых левых скобок, например:

cat >> myfile << - NEWFILE

 

25.2. Скоростной способ вывода документа на печать

Предположим, что нужно создать и вывести на экран небольшой документ, содержащий сообщение. Необязательно использовать редактор vi; вместо этого можно применить метод, показанный в следующем примере. Если после ввода символов QUICKDOC нажать клавишу [Return], документ пересылается на принтер.

$ lpr << QUICKDOC

**** INVITATION**** The Star Trek convention ls in town next week. Be there.

Ticket prices: (please phone)

QUICKDOC

 

25.3. Автоматизация меню

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

Существует сценарий по работе с меню базы данных, который отвечает за резервное копирование баз данных и выполнение административных задач. Меню базы данных применяется в течение дня для выполнения резервирования базы данных и выполнения других административных задач. Если же было принято решение о том, что каждую ночь создаются резервные копии всех баз данных с помощью утилиты cron, отпадает необходимость в создании другого сценария.

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

Главный экран меню, в котором выбран пункт 2, имеет следующий вид.

1: Admin Tasks

2: Sybase Backups

3: Maintenance Tasks Selection > 2

Второй экран меню с выбранным пунктом 3 выглядит так:

1: Backup A Single Database

2: Backup Selected Databases

3: Backup All Databases Selection > 3

Третий экран меню при нажатии клавиши [Y];

   1. dw_levels

   2. dw_based

   3. dw_aggs

Are You Sure You Wish To Backup [Y..N] : Y

Итак, как следует из экрана меню, для резервирования всех баз данных нужно ввести следующую информацию:

   • Название меню сценария, syb_backup.

   • Цифру 2.

   • Цифру 3.

   • Символ Y.

Ниже приводится сценарий, с помощью которого можно автоматически выделить резервные копии баз данных. При этом используется сценарий меню syb_backup:

$ pg auto.sybackup

#!/bin/sh

# задание пути

PATH=/usr/bin:/usr/sbin:/sybase/bin:$LOCALBIN

export PATH

#присваивается значение переменной

DSQUERY=COMET; export DSQUERY

устанавливается значение TERM с последующей инициализацией

TERM=vt220; export TERM

tput -T vt220 init

# журнальный файл для всего потока вывода

log_f=/logs/sql.backup.log

>$1og_f

# ниже приводится код, выполняющий всю эту работу!

/usr/local/sybin/syb_backup >> $log_f 2>&1 << MAYDAY

2

3 Y MAYDAY

chown sybase $1og_f

Далее приводится конструкция фактического перенаправления, которая выполняет все необходимые действия:

usr/local/sybin/syb_backup >> $log_f 2>&1 << MAYDAY

2

3

Y

MAYDAY

Изучая часть кода, связанного с перенаправлением, можно заметить, что в сценарии syb_backup содержится полностью заданный путь; >>$1og_f>&1 означает, что весь поток вывода направляется в файл $1og_f, где находится переменная,

содержащая значение /logs/sql.backup.log. Такой подход довольно удобен, так как впоследствии можно захватить поток вывода, включая подробности резервного копирования и возможные ошибки приложения.

Конструкция "документ здесь" начинается со слова <

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

 

25.4. Автоматизация передачи файлов по протоколу ftp

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

Пароль можно выбрать произвольным образом, однако удобно воспользоваться названием хоста и локальным идентификатором пользователя или электронным, адресом.

Приведенный ниже сценарий запрашивает следующую информацию:

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

   2. Тип передаваемых файлов: двоичный или ASCII.

   3. Имя получаемого файла.

   4. Локальный каталог, в котором размещается выбранный файл.

Когда пользователь вводит наименование удаленного компьютера, с которым устанавливается соединение, для удаленного хоста выполняется команда ttaceroute. Таким образом, можно быть уверенным в том, что соединение действительно установлено. Если же результат выполнения команды traceroute был неудачным, сценарий отображает повторный запрос.

При нажатии клавиши [Return] по умолчанию принимается двоичный режим передачи файлов. После ввода имени загружаемого файла пользователя запрашивают о каталоге назначения для загружаемого файла. По умолчанию этим каталогом служит каталог /tmp. Если пользователь указывает другой каталог, который не может быть найден, используется каталог /tmp.

Именем загружаемого файла будет имя файла с присоединенным к нему расширением .ftp. И, наконец, после того как все эти варианты отображаются и подтверждаются, начинается процесс передачи файлов.

Ниже показано, как выглядят результаты выполнения сценария.

$ ftpauto

Enter the host you wish to access: uniware

Wait… seeing If uniware ls out there..

bumper can see unaware

What type of transfer / receive mode ?

   1. : Binary

   2. : ASCII

Your choice [1…2] [1] :

Enter the name of the file to retrieve :gnutar. Z Enter the directory where the file ls to be placed[/tmp] :

Host to connect ls: uniware

File to get ls : gnutar.Z

Mode to use ls : binary

File to be put in : /tmp/gnutar.Z.ftp

Ready to get file 'y' or 'q' to quit? [y..q] :

Далее приводится соответствующий сценарий.

$ pg ftpauto

#!/bin/sh

#сценарий ftp

#ftpauto

USER=`whoami`

MYDATE=`date +%d/%m/%Y`

THIS_HOST=`hostname -s`

tracelog=/tmp/tracelog.$$

while :

do

# бесконечный цикл

tput clear

cat << MAYDAY

User: $USER $MYDATE

This host: $THIS_HOST

FTP RETRIEVAL SCRIPT

Using the ID of anonymous

MAYDAY

echo -n "Enter the host you wish to access :"

read DEST_HOST

# введено ли имя хоста ???

if [ "$DEST_HOST"="" ]

then

echo "No destination host entered" >&2

exit 1

fi

# можно ли увидеть хост ???

echo "wait..seeing if $DEST_HOST is out there.."

# traceroute проверяет соединение

traceroute $DEST_HOST > $tracelog 2>&1

if grep "unknown host" $tracelog >/dev/null 2>&1; then

echo "Could not locate $DEST_HOST"

echo -n "Try another host? [y..n] :"

read ANS

case $ANS in

y|Y) ;;

*) break;; # выход из бесконечного цикла

esac else

echo "$THIS_HOST can see $DEST_HOST"

break # выход из бесконечного цикла

fi

done

# по умолчанию двоичный режим

echo "What type of transfer /receive mode ?"

echo " 1 : Binary"

echo " 2 : ASCII"

echo -n -e "\fYour choice [1..2] [1]:"

read $TYPE

case $TYPE in

1) MODE=binary;;

2) MODE=ascii;;

*) MODE=binary;;

esac

echo -n " Enter the name of the file to retrieve :"

read FILENAME

if [ "$FILENAME" — "" ]; then

echo "No filename entered" >&2

exit 1

fi

# по умолчанию, это tmp

echo -n -e "\f Enter the directory where the file ls to be placed[/tmp] :"

read DIREC

cd $DIREC >/dev/null 2>&1

# если нельзя перейти в нужный каталог, используйте tmp

if [ "$DIREC"="" ]; then

DIREC=/tmp

fi

if [ $? ! — 0 ] then

echo "$D1REC does not exist placing the file in /tmp anyway"

DIREC=/tmp

fi

echo -e "\t\tHost to connect is: $DEST_HQST"

echo -e "\t\tFile to get is: $FILENAME"

echo -e "\t\tMode to use is: $MODE"

echo -e "\t\tFile to be put in: $DIREC/$FILENAME.ftp"

echo -e -n "\t\tReady to get file 'y' or 'q' to quit? [y..q] :"

read ANS

case $ANS in

Y|y);;

q|Q) exit 0;;

*) exit 0 ;;

esac

echo "ftp.."

ftp -i -n $DEST_HOST << FTPIT

user anonymous $USER@$THIS_HOST

$MODE

get $FILENAME $DIREC/$FILENAME.ftp

quit

FTPIT

if [ -s $DIREC/$FILENAME.ftp ]

then

echo "File ls down"

else

echo "Unable to locate $FILENAME.ftp"

fi

Фактическая конструкция "документ здесь", применяемая при передаче файла с помощью ftp, использует опции ftp -i -n. Эти опции означают "не выводить какие‑либо автоматические запросы регистрации" и "отключение режима интерактивного запроса". Тогда сценарий выполняет регистрацию с помощью команды "user". Паролем является конструкция вида $user@THIS_HOST, которая имеет фактическое значение dave@bumper.

Предположим, что пользователь ежедневно загружает один и тот же файл с помощью одного и того же хоста и, возможно, при этом требуется сохранить определенные данные, полученные за предыдущий день. Тогда пользователю нет необходимости каждый раз вводить имя файла или данные для одного и того же удаленного хоста. Для полей DEST_HOST и filename можно установить значения, заданные по умолчанию. Применение заданных по умолчанию значений позволит не вводить в поля однотипную информацию.

Ниже приводится часть сценария ftpauto, который запрашивает название удаленного хоста. Однако теперь для поля DEST_HOST устанавливается значение, заданное по умолчанию, а именно my_favourite_host. Теперь пользователь может в ответ на запрос ввести другое название для удаленного хоста или нажать клавишу [Return]. Тогда значение, заданное по умолчанию, загружается в переменную DEST_HOST.

Обратите внимание, что нет необходимости проверять, ввел ли пользователь значение. Значение, заданное по умолчанию, присваивается переменной dest_host.

echo -n "Enter the host you wish to access :"

read DEST_HOST

: ${DEST_HQST:="my_favourite_host"}

echo "wait.. seeing if $DEST_HOST is out there.."

traceroute $DEST_HOST >$tracelog 2>$1

 

25.5. Организация доступа к базам данных

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

Одна из систем баз данных 'select into' отключается в том случае, если база данных становится доступной для определенных программных продуктов сторонних производителей. Значит, некоторые базы данных нельзя использовать для ввода произвольных данных или для создания временных таблиц.

Для решения этой проблемы применяется конструкция "документ здесь", С помощью этой конструкции поддерживается связь с системной базой данных, а цикл for применяется для изменения "документа здесь" вместе с названиями баз данных. После установки подключения конструкция "документ здесь" применяется для поддержки команд sql, используемых для задания параметров.

Ниже приводится сценарий, реализующий установку параметров для каждой базы данных:

$ pg set.select

#!/bin/sh

#set.select

#устраняется известная ошибка. Устанавливается выделение в опции db

PATH=$PATH:/sybase/bin:/sybase/install

export PATH

SYBASE="/sybase"; export SYBASE

DSQUERY=ACESRV; export DSQUERY

PASSWORD="prilog"

DATABASES="dwbased tempdb aggs levels reps accounts"

for loop in $DATABASES

do

su Sybase -c '/sybase/bin/isql -Usa -P$PASSWORD' << MAYDAY

use master

go

sp_dboption $LOOP,"select into/bulkcopy/pllsort", true

go

use $LOOP go

checkpoint go

MAYDAY

done

Рассматривая конструкцию "документ здесь", при выполнении вышеуказанной команды интерпретатор shell оценивает приведенный выше код.

use master

go

sp_dboption dwbased,"select into/bulkcopy/pllsort", true

go

use dw_based

go

checkpoint go

Когда интерпретатор shell просматривает завершающее слово mayday, сценарий начинает следующую итерацию для цикла for. При этом из списка выбирается следующая база данных. При выполнении сценария получаются следующие результаты:

$ set.select

Database option 'select into/bulkcopy/pllsort' turned ON for database

'dwbased'.

Run the CHECKPOINT command in the database that was changed.

(return status=0)

Database option 'select into/bulkcopy/pllsort' turned ON for database 'tempdb'.

Run the CHECKPOINT command in the database that was changed, (return status=0)

Database option 'select into/bulkcopy/pllsort' turned ON for database 'aggs'.

Run the CHECKPOINT command in the database that was changed, (return status=0)

25.6. Заключение

В главе содержатся примеры по автоматизации задач с использованием конструкции "документ здесь". Конструкцию "документ здесь" можно применять при решении большого количества задач, особенно при установке подключения к приложениям или выполнении команды ftping. Приведенные сценарии можно выполнять и модифицировать для решения конкретных задач конечного пользователя.

 

ГЛАВА 26

 

Утилиты интерпретатора shell

В этой главе рассматриваются следующие темы:

   • создание датируемых имен файлов и временных файлов;

   • сигналы;

   • команда trap и способы перехвата сигналов;

   • команда eval;

   • команда logger.

 

26.1. Создание регистрационных файлов

 

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

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

 

26.1.1. Применение команды date для создания журнальных файлов

Если возникла необходимость создать журнальный файл, желательно сделать его уникальным. Для этого достаточно воспользоваться командой date. Командой date можно манипулировать, а также добавлять ее к имени файла, который станет журнальным файлом.

Для изменения формата отображения данных применяется следующий формат:

date option + %format

С помощью знака плюс (+( можно в различных форматах отображать текущую дату. Ниже дата отображается в формате день, месяц, год.

$ date +%d%m%y

090699

Приведем некоторые наиболее часто применяемые форматы данных.

$ date +%d-%m-%y

09-06-99

$ date +%A%e" "%B" "%Y

Wednesday 9 June 1999

Отображение времени в формате чч: мм: $ date +%R

10:07

$ date +%A" "W "%p Wednesday 10:09 AM

Отображение времени в расширенном формате: $ date +%T

10:29:41

$ date +%A" "%T

Wednesday 10:31:19

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

Для использования даты в качестве части имени файла проще всего воспользоваться подстановкой. Введите переменную, значением которой является заново отформатированная дата, и присоедините эту переменную к имени файла. Этим именем и будет назван журнальный файл.

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

Сценарий имеет вид:

$ pg log

#!/bin/sh

# регистрация

#

MYDATE=`date +%d%m%y`

#присоединение MYDATE к переменной LOGFILE, которая содержит действительное #имя файла регистрации.

LOGFILE=/logs/backup_log.$MYDATE

#создание файла

>$LOGFILE

MVTTIME= `date +%d%R` LOGFILE2=/logs/admin_log.$MYTIME

# создание файла

>$LOGFILE2

При выполнении этого сценария создаются два журнальных файла.

backup_log.09069 9 admin_log.09l6:18

 

26.1.2. Создание уникальных временных файлов

При рассмотрении специальных переменных уже обсуждалась переменная $$ Она содержит ID или номер процесса, выполняющегося в текущий момент. Эти сведения применяются при создании временных файлов в текущем сценарии, поскольку ID процесса уникален в рамках сценария. Достаточно лишь создать файл и присоединить к нему символ $$, После завершения можно удалить все файлы, имеющие символ $$ в качестве расширения. Интерпретатор shell оценивает переменную $$ как текущий ID процесса и удаляет эти файлы, но оставляет файлы, к которым присоединен ID процесса.

В командной строке введите следующую команду:

$ echo $$

281

Это значение ID процесса приведено для примера; в вашем случае, скорее всего, будет получено другое значение. Если создать новый сеанс и ввести эту же команду, получится другой номер, поскольку будет запущен иной процесс.

$ echo $$

382

Ниже приводится сценарий, который создает два временных файла, обрабатывает и затем удаляет их.

$ pg tempfiles

#!/bin/sh

#tempfiles

#именование временных файлов

HOLD1=/tmp/hold1.$$

HOLD2=/tmp/hold2.$$

#выполнение определенной обработки с помощью этих файлов

df -tk > $HOLD1

cat $HOLD1 > $HOLD2

# удаление файлов

rm /tmp/*.$$

При выполнении этого сценария создаются следующие два файла.

hold1.408 hold2.408

Когда указывается команда rm /tmp/*.$$, интерпретатор shell в действительности выполняет команду rm /tmp/*.408.

Важно помнить, что ID процесса является уникальным только в конкретный момент времени. Например, если приведенный выше сценарий выполнить снова, получим новый ID процесса, поскольку речь идет о другом процессе.

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

Временные файлы создаются легко и быстро; кроме того, они являются уникальными для данного процесса. После того как сценарий завершает обработку, их несложно удалить без искажения остальной информации.

 

26.2. Сигналы

 

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

Номер сигнала Название сигнала Значение
1 SIGHUP "Зависание" или прекращение выполнения родительского процесса
2 SIG1NT Прерывание с помощью клавиатуры; обычно используется комбинация клавиш [Ctrl+C]
3 SIGQUIT Завершение выполнения с помощью клавиатуры
9 SIGKILL Прекращение выполнения определенного процесса
11 SIGSEGV Нарушение сегментации (память(
15 SIGTERM Завершение выполнения программы (завершение выполнения программы, заданное по умолчанию)

Существует сигнал 0, который ранее уже рассматривался (при создании файла .logout). Этот сигнал является сигналом "выхода из интерпретатора shell". Чтобы переслать сигнал 0, введите в командную строку команду exit либо примените к процессу или укажите в командной строке комбинацию клавиш [Ctrl+D].

Для пересылки сигнала используется формат:

kill [- номер сигнала:| имя сигнала] ID процесса

Если команда kill вводится без указания номера или названия сигнала, то она по умолчанию относится к сигналу с номером 15. Для просмотра списка всех сигналов примените следующую команду:

$ kill -1
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGIOT 7} SIGBUS 8) SIGFPE
9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
13) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD
18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN
22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO
30) SIGPWR

 

26.2.1. Уничтожение процесса

При пересылке сигнала 1 процесс заново считывает файл конфигурации. Например, если при выполнении процесса под названием демон dns файлы базы данных изменяются, не следует уничтожать демон и заново запускать его. Выполните всего лишь команду kill -1. В этом случае файлы конфигурации просматриваются заново.

Ниже приводится пример пересылки сигнала 9 (гарантированное уничтожение) для уничтожения процесса mon_web, который выполняется в системе. Сначала примените команду ps для создания процесса.

$ ps -ef | grep mon_web | grep -v root

157 ? S 0:00 mon_web

Если в системе не поддерживается команда ps -ef, то воспользуйтесь командой ps xa. Для уничтожения процесса можно применить команду:

kill -9 157

или

kill -s SIGKILL 157

В некоторых системах можно не указывать опцию -s. Например, введите команду

kill SIGKILL 157

В приведенном ниже сценарии уничтожение процесса основано на использовании имени процесса. Имя устраняемого процесса указывается в виде параметра. Выполняется проверка, что данный процесс был действительно уничтожен. Утилита grep используется для обнаружения всех совпадающих имен процесса. Если соответствующие имена обнаруживаются, поступает запрос пользователю, следует ли уничтожить найденные процессы. Для уничтожения процесса применяется команда kill -9.

Соответствующий сценарий выглядит следующим образом:

$ pg pskill

#!/bin/sh

# pskill

HOLD1=/tmp/HOLD1.$$

PROCESS=$1

usage () {

# usage

echo "Usage :''`basename $0` process_name"

exit 1

}

if [ $# -ne 1 ]; then

usage

fi

case $1 in

*)

применение программы grep для исключения нашего сценария из вывода команды ps

извлечение полей 1 и 6, перенаправление во временный файл

ps x | grep $PROCESS | grep -v $0 | awk '{print $1"\t" $6}'>$HOLD1

# ps -ef |.. если команда ps x не срабатывает

;;

esac

#есть ли файл??

if [ ! -s $HOLD1 ]; then

echo "No processes found…sorry"

exit 1

fi

#просмотр содержимого временного файла и отображение значений полей

while read LOOP1 LOOP2

do

echo $LOOP1 $LOOP2

done <$HOLD1

echo -n "Are these the processes to be killed? [y..n] >"

read ANS

case $ANS in

Y|y) while read LOOP1 LOOP2

do

echo $LOOP1

kill -9 $LOOP1 done

<$HOLD1

rm /tmp/*.$$

;;

N|n);;

esac

При выполнении сценария поток вывода имеет вид:

$ pskill web

1760 ./webmon

1761 /usr/apps/web_col

Are these the processes to be killed? [y..n] >y

1760 1761 [1]+ Killed webmon

Чтобы убедиться в том, что процесс уничтожен, введите команду повторно:

$ pskill web

No processes found..sorry

 

26.2.2. Обнаружение сигнала

Некоторые сигналы можно захватить и выполнить соответствующие действия. Другие сигналы нельзя уловить. Например, если команда получает сигнал 9, пользователю не нужно предпринимать какие‑либо действия.

Если ограничиться написанием сценариев, следует обращать внимание только на сигналы 1,2,3 и 15. Если сценарий получает сигнал, возможен один из трех вариантов дальнейших действий: 1. Ничего не предпринимать, система самостоятельно отреагирует на полученный

сигнал.

   1. Захватить сигнал, но игнорировать его.

   2. Захватить сигнал и предпринять определенные действия.

Большинство сценариев используют сигнал с номером 1. Этот метод применяется далее в книге во всех сценариях.

Чтобы применить два других метода, нужно воспользоваться командой trap.

 

26.3. Команда trap

 

Команда trap позволяет перехватывать сигналы. Формат команды trap:

trap "имя" сигнал(ы)

Имя представляет собой функцию, содержащую инструкции, которые выполняются при перехвате сигнала. В действительности функцию следует называть так, чтобы ее имя было связано именно с перехваченными сигналами. Имя следует заключать в двойные кавычки (""). Сигналы являются входящими.

Когда сигнал перехватывается, сценарий обычно находится в стадии обработки. Самые распространенные действия следующие:

   1. Очистить временные файлы.

   2. Игнорировать сигналы.

   3. Запросить пользователя, следует ли завершить сценарий.

Ниже приводится таблица, где описаны наиболее распространенные варианты применения команды trap:

trap "" 2 3

Игнорирование сигналов 2 и 3; пользователь не может

завершить сценарий

trap "команды" 2 3

Если захвачены сигналы 2 и 3, выполняются команды

trap 2 3

Восстановление сигналов 2 и 3; пользователь может завер-

шить сценарий

Вместо двойных кавычек можно использовать одинарные; результат будет аналогичен.

 

26.3.1. Перехват сигналов и выполнение действий

А теперь создадим сценарий, выполняющий подсчет итераций до тех пор, пока пользователь не нажмет комбинацию клавиш [Ctrl+C] (сигнал 2). После этого сценарий отобразит сообщение, содержащее номер текущей итерации цикла.

В этом случае применяется следующий формат:

trap "какие‑либо действия" номер сигнала: (s)

Соответствующий сценарий имеет вид:

$ pg trap1

#!/bin/sh

#trap1

trap "my_exit" 2

LOOP=0

my_exit ()

{

echo "You just hit , at number $LOOP"

echo " I will now exit "

exit 1

}

while : do

LOOP=`expr $LOOP + 1`

echo $LOOP

done

Рассмотрим сценарий более подробно.

trap "my_exit" 2

В результате выполнения команды trap после получения сигнала 2 выполняется команда, заключенная в двойные кавычки; в данном случае вызывается функция

my_exit.

my_exit ()

{

echo "You just hit , at number $LOOP"

echo " I will now exit "

exit 1

}

Функция myexit вызывается при получении сигнала 2; при этом отображается значение переменной $LOOP, информирующее пользователя о том, какая итерация цикла выполнялась при нажатии комбинации клавиш [Ctrl+C]. Функции подобного типа применяются на практике для удаления временных файлов.

При выполнении сценария получим следующие результаты:

$ trap1

211 212

You just hit , at number 213 I will now exit

 

26.3.2. Захват сигнала и выполнение действий

Наиболее часто выполняемым действием является удаление временных файлов.

В следующем сценарии с помощью команд df и ps непрерывно добавляется информация во временные файлы HOLD1.$$ и HOLD2.$$. Не забывайте, что символы $$ заменяют ID процесса. Когда пользователь нажимает комбинацию клавиш [Ctrl+C], эти файлы удаляются.

$ pg trap2

#!/bin/sh

# trap2

# перехват только сигнала 2….

trap "my_exit" 2

HOLD1=/tmp/HOLD1.$$

HOLD2=/tmp/HOLD2.$$

my_exit {)

{

# my_exit

echo " detected..Now cleaning up..wait"

# удаление временных файлов

rm /tmp/*.$$ 2>/dev/null

exit 1

}

echo "processing…."

# основной цикл

while :

do

df >> $HOLD1

ps xa >>$HOLD2

done

Результаты выполнении этого сценария будут следующими:

$ trap2

processing….

detected..Now cleaning up..wait

При получении сигнала можно предоставлять пользователю определенный выбор. Однако если получены сигналы 2 или 3, следует убедиться, что они не появились случайно. Необходимо предусмотреть поток ошибок, благодаря чему выявляется ошибочное нажатие клавиш [Ctrl+C].

В следующем примере пользователю предоставляется возможность решить, следует ли выйти из сценария после получения сигнала 2. Отображается запрос о том, действительно ли пользователь желает завершить работу. Для уточнения предпринимаемого действия применяется конструкция case.

Если пользователь желает выйти из сценария, он выбирает 1, в результате чего после отображения статуса "exit 1" запускается процесс очистки. Если пользователь не желает выходить из сценария, никакие действия не производятся; зададим, что при выполнении конструкции case результаты выбора будут неудачными и произойдет возврат к исходному коду. Конечно, при подтверждении должны захватываться значения всех пустых полей.

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

my_exit () {

# my_exit

echo -e "\nReceived interrupt …"

echo "Do you really wish to exit ???"

echo " 1: Yes" echo " 2: No"

echo -n " Your choice [1..2] >"

read ANS

case $ANS in

1) # удаление временных файлов.. и т. д…

exit 1

;;

# не выполняет ничего

;; esac

}

Соответствующий сценарий выглядит так:

$ pg trap4

#!/bin/sh

#trap4

#перехват сигналов 1 2 3 и 15

trap "my_exit" 1 2 3 15

LOOP=0

# временные файлы

HOLD1=/tmp/HOLD1.$$

HOLD2=/tmp/HOLD2.$$

my_exit() {

# функция my_exit

echo -e "\nRecieved interrupt…"

echo "Do you wish to really exit ???"

echo " Y: Yes"

echo " N: No"

echo -n " Your choice [Y..N] >"

read ANS

case $ANS in

Y|y) exit 1;; # выход из сценария

N|n) ;; # возврат к обычной обработке

esac

}

# цикл while применяется здесь, например, для просмотра полей

echo -n "Enter your name :"

read NAME

echo -n "Enter your age :"

read AGE

Если при выполнении этого сценария происходит нажатие клавиш [Ctrl+C] в середине поля ввода (сразу после начала ввода имени), то пользователю предоставляется выбор: возвратиться к обычной обработке или выйти из сценария.

$ trap4

Enter your name :David Та

Received interrupt…

Do you really wish to exit ???

1: Yes

2: No

Your choice [1. .2] >2

Enter your age :

 

26.3.3. Блокировка терминала

Ниже приводится сценарий, в котором предлагается другой путь для перехвата сигналов в функционирующем сценарии. Сценарий lockit блокирует терминал пользователя с помощью командной строки. При этом командная строка помещается в непрерывный цикл while. Команда trap захватывает сигналы 2, 3 и 15. Если пользователь пытается прервать выполнение сценария, отображается сообщение о том, что действия пользователя не были успешными.

При первом обращении к сценарию запрашивается пароль. Для отмены блокировки терминала сведения поступают из устройства /dev/tty, следовательно, отсутствует запрос на разблокировку терминала; нужно просто ввести пароль и нажать клавишу ввода.

Если пользователь забыл пароль, нужно зарегистрироваться на другом терминале и устранить сценарий. Проверка длины пароля не производится, но при желании ее можно установить.

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

$ stty sane

Сценарий имеет вид:

$ pg lockit

#!/bin/sh

#lockit

#перехват сигналов 2 3 и 15

trap "nice_try" 2 3 15

#устройство, на котором выполняется сценарий

TTY=`tty`

nice_try () {

# nice_try

echo "Nice try, the terminal stays locked"

}

# сохраните настройки stty, скрытие символов при вводе пароля

SAVEDSTTY=`stty -g`

stty -echo

echo -n "Enter your password to lock $TTY :"

read PASSWORD

clear

while : do

# чтение только из tty !!

read RESPONSE < $TTY

if [ "$RESPONSE"="$PASSWORD" ]; then

# пароль соответствует…разблокировка

echo "unlocking…"

break

fi

#отображение сообщения, если пользователь введет неверный пароль

#или нажмет клавишу ввода

echo "wrong password and terminal is locked.."

done

# восстановление настроек stty stty=$SAVEDSTTY

Вывод сценария lockit:

$ lockit

Enter your password to lock /dev/tty1 :

Затем экран очищается. При нажатии клавиши ввода или наборе неверного пароля сценарии выводит следующие данные:

wrong password and terminal is locked..

Nice try, the terminal stays locked

wrong password and terminal is locked..

Nice try, the terminal stays locked '

wrong password and terminal is locked..

Введите правильный пароль

unlocking… $

Теперь возвращаемся обратно, в командную строку.

 

26.3.4. Игнорирование сигналов

Когда пользователь регистрируется в системе, просматривается файл /etc/profile; нежелательно, чтобы пользователь прерывал этот процесс. Обычно задается перехват, или игнорирование, сигналов 1, 2, 3 и 15, но потом при просмотре сообщения motd (ежедневного сообщения) их подключают вновь (восстанавливают). Затем для игнорирования сигналов 1, 2, 3 и 15 снова устанавливается перехват.

Аналогичный подход можно, реализовать при работе со сценариями. Можно ввести понятие критического момента, который наступает при открытии большого количества файлов. Начиная с этого момента, нельзя прерывать выполнение сценария, поскольку это может повредить файлы. Для решения этой проблемы следует установить, команду trap, что позволит игнорировать некоторые сигналы. Когда завершится критический момент в функционировании сценария, примените команду trap, чтобы снова можно было захватывать сигналы.

Для игнорирования входящих сигналов (кроме сигнала 9) применяется следующая команда:

trap "" номер_сигнала:{n}

Обратите внимание, что двойные кавычки ничего не содержат. Чтобы восстановить перехват и заново захватывать сигналы, выполните команду:

trap "любые действия" номер_сигнала:{n}

Суммируем сведения о процессах игнорирования и выявления сигналов.

trap "" 1 2 3 15 # игнорирование сигналов code that does really critical stuff

trap "my_exit" 1 2 3 15 # выполните снова захват сигналов с помощью функции

# my_exit

Обратите внимание на сценарий, выполняющий критическую обработку. Цикл while аккуратно передвигает имеющийся критический момент. Для игнорирования сигналов 2, 3 и 15 применяется команда trap. После завершения цикла while, завершается еще один цикл while, но перехват уже восстановлен и прерывания разрешены.

Оба цикла while выполняются до завершения шести итераций, затем в цикле активизируется команда sleep. Благодаря этому имеется достаточно времени для того, чтобы прервать выполнение сценария.

Рассмотрим следующий сценарий:

$ pg trap_ignore

#!/bin/sh

#trap_ignore

#игнорирование сигналов

trap "" 1 2 3 15

LOOP=0

my_exit ()

# my_exit

{

echo "Received interrupt on count $LOOP"

echo "Now exiting…" exit 1

}

# критическая обработка, нельзя прерывать….

LOOP=0

while : do

LOOP=`expr $LOOP + 1`

echo "critical processing..$LOOP..you cannot interrupt me"

sleep 1

if [ "$LOOP" -eq 6 ]; then

break

fi

done

LOOP=0

#критическая обработка завершена, перехват задан снова, но разрешены прерывания

trap "my_exit" 1 2 3 15

while :

do

LOOP=`expr $LOOP + 1`

echo "Non‑critical processing..$LOOP..interrupt me now if you want"

sleep 1

if [ "$LOOP" -eq 6 ]; then

break

fi

done

Если в процессе работы этого сценария попытаться нажать клавиши [Ctrl+C] во время выполнения первого цикла "критической обработки", ничего не произойдет. Это связано с тем, что была введена команда trap для игнорирования сигналов.

После того как начинается второй цикл "некритической обработки", статус команды trap восстанавливается, в результате чего разрешаются прерывания.

$ trap_ignore

critical processing..1..you cannot interrupt me

critical processing..2..you cannot interrupt me

critical processing..3..you cannot interrupt me

critical processing..4..you cannot interrupt me

critical processing..5..you cannot interrupt me

critical processing..6..you cannot interrupt me

Non‑critical processing..1..interrupt me now if you want

Non‑critical processing..2..interrupt me now if you want

Received interrupt on count 2

Now exiting…

Благодаря применению команды trap можно обрести большую степень контроля над "поведением" сценария при получении сигнала. Перехват и последующая обработка сигналов обеспечивают устойчивую работу сценариев.

 

26.4. Команда eval

 

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

Команда eval также может применяться для отображения значений простых переменных; эти переменные не должны быть сложными.

$ NAME=Honeysuckle

$ eval echo $NAME

Honeysuckle

$ echo $NAME

Honeysuckle

Наилучшим методом для понимания работы команды eval является изучение оценки командной строки, выполняемой этой командой.

 

26.4.1. Выполнение команд, находящихся в строке

Вначале создадим небольшой файл, testf, содержащий некоторый текст. Затем переменной myfile будет присвоена команда cat testf с последующим отображением значения переменной. Благодаря этому можно проверить возможность отображения на экране содержимого файла testf.

$ pg testf

May Day, May Day Going Down

Присвоим переменной myfile строку "cat testf:

$ MYFILE="cat testf"

Если требуется вывести содержимое файла testf на экран, нужно выполнить команду cat testf.

$ echo $MYFILE

cat testf

Теперь применим команду eval для оценки значения переменной; при этом следует помнить, что eval выполняет два прохода при оценке переменной myfile.

$ eval $MYFILE

May Day, May Day Going Down

В результате этого успешно оценивается значение переменной и применяется команда cat к файлу testf. При первом проходе отображается фактическая строка "cat testf", при втором проходе выполняется содержимое строки, в данном случае cat testf.

Рассмотрим другой пример. Переменной cat_passwd будет присвоена строка "cat /etc/passwd | more". Команда eval выполняет оценку содержимого данной строки.

$ CAT_PASSWD=`cat /etc/passwd | more`

$ echo $CAT_PASSWD

cat /etc/passwd|more

$ eval

$CAT_PASSWD

root:HccPbzT5tbOOg:0:0:root:/root:/bin/sh

bin:*:l:l:bin:/bin:

daemon:*:2:2:daemon:/sbin:

adm:*:3:4:ada:/var/adm:

Команда eval также хорошо подходит для отображения значения последнего параметра, передаваемого сценарию. Значение последнего параметра уже отображалось, но в этом случае оно будет отображено снова.

$ pg evalit

#!/bin/sh

# сценарий evalit

echo " Total number of arguments passed is $#"

echo " The process ID is $$"

echo "' Last argument is "$(eval echo \$$)

При выполнении этого сценария получим следующий результат (ID процесса может отличаться от случая к случаю):

$ evalit alpha bravo charlie

Total number of arguments passed is 3

The process ID is 780

Last argument is Charlie

В этом сценарии команда eval сначала оценивает значение переменной $$ в сравнении с ID процесса, а при выполнении второго прохода производится оценка последнего параметра, передаваемого переменной.

 

26.4.2. Присвоение значения имени переменной

Можно также поставить в соответствие полю данных имя переменной. Рассмотрим, что это означает на практике. Предположим, что в нашем распоряжении имеется следующий файл:

$ pg data

PC 486 MONITOR svga NETWORK yes

Нам необходимо, чтобы первому столбцу текста соответствовали имена переменных, а второму столбцу текста — значения соответствующих переменных. При этом должно отображаться следующее:

echo $PC

466

Как же можно достичь желаемого результата? Ниже приведен соответствующий сценарий, использующий команду eval.

$ pg eval_it

#!/bin/sh

#сценарий eval_it

while read NAME TYPE

do

eval `echo "${NAME}=${TYPE}"`

done < data

echo "You have a $PC pc, with a $MONITOR monitor"

echo "and have you network? $NETWORK"

Рассмотрим, как функционирует сценарий. Сначала берутся значения рс и 486, которые присваиваются переменным name и type соответственно. При первом проходе команда eval отображает на экране два значения переменных, PC и 486; во время выполнения второго прохода вместо переменной name подставляется значение рс, а вместо переменной type — значение 486. При выполнении сценария получаются следующие результаты:

$ eval_it

You have a 486 рс, with a svga monitor and have you network? yes

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

 

26.5. Команда logger

 

В системе поддерживается достаточно много журнальных файлов. Некоторые из них, именуемые messages, обычно размещены в каталоге /var/adm или /var/log. Сообщения, регистрируемые в этом файле, передаются с помощью файла конфигурации syslog и имеют строго заданный формат. Чтобы убедиться, что система сконфигурирована для генерирования сообщений из программ, проверьте файл /etc/syslog.conf. Этот файл содержит описания приоритетов и свойств, которые программа может использовать для отсылки различных типов сообщений.

Здесь мы не будем подобно рассматривать, каким образом UNIX либо Linux регистрирует сообщения в файле. Все, что вам требуется пока знать, это номера различных уровней сообщений (от информационных до критических).

Сообщения могут отсылаться в файл с помощью команды logger. Перед тем как использовать эту команду, нужно обратиться к справочной странице man, так как различные версии этой команды могут иметь отличающийся синтаксис. Поскольку в этой главе рассматриваются только информационные сообщения, нужно обратить внимание на соответствующие команды, рассматриваемые далее.

Необходимость отправки сообщений в файл диктуется одной из следующих причин:

   • количество попыток доступа/регистрации за определенный период;

   • критическая обработка одного из сбойных сценариев;

   • мониторинг отчетов сценариев.

Ниже показано, как выглядит файл /var/adm/messages. Формат этого файла может немного отличаться от данного образца:

$ tail /var/adm/messages

Jun 16 20:59:03 localhost login[281]: DIALUP AT ttyS1 BY root

Jun 16 20:59:03 localhost login[281]: ROOT LOGIN ON tty$1

Jun 16 20:59:04 localhost PAM_pwdb [281] : (login) session closed for user root

Jun 16 21:56:38 localhost named[211: Cleaned cache of 0 RRs]

Jun 16 21:56:39 localhost named[211]: USAGE 929570318 929566719

Jun 16 21:56:39 localhost named[211]: NSTATS 929570318 929566719

Общий формат команды logger выглядит так:

logger -p -i message

Параметры этой команды выполняют следующие функции:

-p Определяет приоритет; в данном случае затрагивается только файл user.notice,

который всегда является используемым по умолчанию

-i Регистрирует ID процесса для каждого сообщения

 

26.5.1. Использование команды logger

В командной строке интерпретатора shell введите следующую команду:

$ logger -p notice "This is a test message. Please Ignore $LOGNAME"

Возможно, вам придется подождать пару минут, пока не отобразится информация о регистрации сообщения.

$ tail /var/adm/messages

Jun 17 10:36:49 acers6 dave: This is a test message. Please Ignore dave

Из приведенного примера видно, что регистрируется, пользователь, выполняющий регистрацию сообщения.

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

$ pg test_logger

#!/bin/sh

# test_logger

logger -p notice "`basename $0`: there are currently `who |wc -l` users on the system"

Запустим сценарий.

$ test_logger

Теперь отобразим содержимое файла сообщений.

$ tail /var/adm/messages

Jun 17 11:02:53 acers6 dave: test_logger:there are currently 15 users on the system

 

26.5.2. Использование команды logger в сценариях

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

В следующем сценарии очистки при получении любого из сигналов с номерами 2, 3 или 15 производится регистрация сообщения.

$ pg cleanup

#!/bin/sh

#cleanup

#очистка журнальных файлов системы

trap "my_exit" 2 3 15

my_exit () {

# my_exit

logger -p notice "`basename $0`: Was killed while cleaning up system logs..CHECK OUT ANY DAMAGE"

exit 1

}

tail -3200c /var/adm/utmp > /tmp/utmp

mv /tmp/utmp /var/adm/utmp

>/var/adm/wtmp

#

tail -10 /var/adm/sulog > /tmp/o_sulog

mv /tmp/o_sulog /var/adm/sulog

При просмотре файла сообщений можно заметить, что возникла проблема, связанная с выполнением сценария очистки.

$ tail /var/adm/messages

Jun 17 11:34:28 acers6 dave: cleanup:Was killed whilst cleaning up systemlogs.. CHECK OUT ANY DAMAGE

Помимо использования при работе с различными критическими сценариями, команду logger можно также применять для регистрации любых подключений удаленных пользователей к системе. Ниже приведен сегмент кода, регистрирующий пользователей, которые подключаются к системе с помощью последовательных линий tty0 и tty2. Этот фрагмент кода берет свое начало от одного из файлов /etc/profile.

TTY_LINE=`tty`

case $TTY_LINE in

"/dev/tty0") TERM=ibm3151 ;;

"/dev/tty2") TERM=vt220

#проверка пользователей, которым разрешен доступ к модемной линии

#

echo "This is a modem connection"

# modemf содержит регистрационные имена для допустимых пользователей

modemf=/usr/local/etc/modem.users

if [ -s $modemf ] then

user=`cat $modemf | awk '{print $1}' | grep $LOGNAME`

# если имя не содержится в файле, пользователь не допускается в систему

if [ "$USER" != "$LOGNAME" ]

then

echo "INVALID USER FOR MODEM CONNECTION"

echo " DISCONNECTING………"

sleep 1

exit 1

else

echo "modem connection allowed"

fi

fi

logger -p notice "modem line connect $TTY_LINE… $LOGNAME"

;;

*) TERM=vt220

stty erase '^h' ;;

esac

Команда logger является превосходным инструментальным средством, применяемым для регистрации информации в глобальных файлах сообщений системы.

 

26.6. Заключение

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

 

ГЛАВА 27

 

Небольшая коллекция сценариев

В настоящей главе содержатся примеры некоторых наиболее распространенных сценариев. Изучая их, можно заметить, что все они невелики по размеру и довольно просты. В этом и состоит преимущество использования сценариев; они не должны быть сложными и объемными, поскольку сценарии создаются с целью экономии времени пользователя.

Конечно, в состав данной главы неплохо было бы включить сценарий comet, выполняющий общую проверку баз данных. Но поскольку этот сценарий содержит более 500 строк, нецелесообразно включать его в эту небольшую книгу. Разаботка сценария comet началась еще пару лет назад. Тогда этот сценарий состоял не более чем из пяти строк. Но в ходе естественного процесса эволюции величина сценария существенно выросла. Приведем перечень сценариев, рассматриваемых в данной главе:

pingall Сценарий, использующий записи из файла /etc/hosts для выполнения опроса всех хостов
backup_gen Общий сценарий резервного копирования, который загружает заданные по умолчанию настройки
del.lines Оболочка потокового редактора sed, выполняющая удаление строк из файлов
access deny Утилита, реализующая запрет доступа для определенных пользователей при выполнении регистрации
logroll Утилита, реализующая прокрутку журнального файла в случае, если он достигает определенного размера
nfsdown Утилита, реализующая быстрый метод демонтирования всех каталогов nfs

 

27.1. Сценарий pingall

Еще несколько лет назад сценарий pingall представлял собой часть общего сценария отчета, который выполнялся по ночам. Этот сценарий опрашивает все хосты, записи о которых находятся в файле hosts.

Сценарий реализует просмотр файла /etc/hosts и разыскивает все строки, которые не начинаются с символа #. Затем цикл while считывает строки отфильтрованного текста. Для присваивания переменной addr значения первого поля отфильтрованного текста используется утилита awk. Затем с помощью цикла for по каждому найденному адресу отправляется запрос.

Ниже приводится сам сценарий.

$ pg pingall

#!/bin/sh

# pingall

# просмотр файла /etc/hosts и отправка запроса по каждому адресу

cat /etc/hosts | grep -v '^#' | while read LINE

do

ADDR=`awk '{print $1}'`

for MACHINE in $ADDR

do

ping -s -c1 $MACHINE

done

done

Сценарий pingall можно легко расширить и включить в него функции отчетов, связанные с другими сетевыми утилитами.

 

27.2. Сценарий backup_gen

Сценарий backup_gen приводится здесь вовсе не для иллюстрации методики резервирования каталогов. Этот сценарий является удачным примером совместного использования настроек, общих для нескольких сценариев.

Сценарий backup_gen предназначен для создания резервных копий. При выполнении сценария просматривается заданный по умолчанию файл конфигурации, который затем используется для резервирования системы. При желании пользователь может изменять настройки, заданные по умолчанию. Сценарий является отличным примером того, как различные сценарии могут применять одинаковые настройки или изменять их во время выполнения сценария. После запуска сценария выполняется проверка на наличие исходного файла (backup.defaults). Если этот файл не найден, сценарий завершается.

При выполнении сценария отображается заголовок экрана и настройки, заданные по умолчанию. Пользователю направляется запрос о том, требуется ли изменять какие‑либо настройки, заданные по умолчанию. Если ответ положителен, поступает запрос на ввод кода, применяемого для изменения необходимых настроек. Для ввода правильного кода пользователю предоставляются три попытки; если введен неверный код, используются настройки, заданные по умолчанию. При вводе корректного кода пользователь может изменить приведенные ниже настройки (значения, заданные по умолчанию, содержатся в квадратных скобках []):

tape device [rmt0] Можно выбрать rmt1 и rmt3
mail admin when the backup has finished [yes] Нет вариантов выбора
type of backup [full] Можно выбрать опцию
normal или sybase

Изменения настроек выполняются с помощью временных переменных. Для получения доступа к заданным по умолчанию настройкам установите курсор мыши в любом поле и нажмите клавишу [Return]. Однако следующие настройки изменять нельзя:

backup log filename code name.

Все внесенные изменения затем подтверждаются. После завершения процесса подтверждения значения временных переменных снова присваиваются исходным переменным. До завершения резервного копирования выполняется тестирование магнитной ленты. В процессе резервного копирования применяются команды find и cpio. С помощью этих команд используются переменные из файла настроек или значения новых переменных, указанные пользователем.

Далее приводится соответствующий сценарий.

$ pg backup_run

#!/bin/sh

#backup_run

#сценарий выполнения резервного копирования

#загрузка файла с конфигурационными параметрами

SOURCE=/appdva/bin/backup.defaults

check_source ()

{

#check_source

#файл backup.defaults содержит параметры конфигурации/функции

#проверка того, что путь содержит нужный каталог

if [ -r $SOURCE ]; then

. $SOURCE

else

echo "`basename $0`: cannot locate defaults file"

exit 1

fi

}

header () {

# header

USER=`whoami`

MYDATE=`date + %A" "%e" of "%B-%Y`

clear

cat << MAYDAY

User : $USER $MYDATE

NETWORK SYSTEM BACKUP

MAYDAY

}

change_settings () {

# change_settings

# отображение параметров, заданных по умолчанию

header

echo "Valid Entries Are…"

echo "Tape Device: rmt0, rmt1, rmt3"

echo "Mail Admin: yes, no"

echo "Backup Type: full, normal, sybase "

while :

do

echo -n -c "\n\n Tape Device To Be Used For This Backup [$_DEVICE] :"

read T_DEVICE

: ${T_DEVICE:=$_DEVICE}

case $T_DEVICE in

rmt0|rmt1|rmt3) break;;

*) echo "The devices are either… rmt0, rmt1, rmt3"

esac

done

#если пользователь нажимает клавишу ввода при установке курсора в любом

#из полей, применяются настройки, заданные по умолчанию

while :

do

echo -n "Mail Admin When Done [$INFORM] :"

read T_INFORM

: ${T_INFORM:=$_INFORM}

case $T_INFORM in

yes|Yes) break;;

no|No) break;;

*) echo "The choices are yes, no";;

esac

done

while :

do

echo -n " Backup Type [$_TYPE] :"

read T_TYPE

: ${T_TYPE:=$_TYPE}

case $T_TYPE in

Full|full) breaks;;

Normal|normal)break;;

Sybase|sybase)break;;

*) echo "The choices are either… full, normal, sybase";;

esac

done

#повторное присваивание значений временных переменных исходным переменным,

#которые были загружены

_DEVICE=$T_DEVICE;

_INFORM=$T_INFORM;

_INFORM=$T_INFORM

}

show_settings ()

# отображение текущих настроек

{

cat << MAYDAY

Default Settings Are…

Tape Device To Be Used : $_DEVICE

Mail Admin When Done : $_INFORM

Type Of Backup : $_TYPE

Log file of backup : $_LOGFILE

MAYDAY

}

get_code ()

{

#пользователи имеют 3 попытки для ввода правильного кода

#_CODE загружается из исходного файла

clear

header

_COUNTER=0

echo "YOU MUST ENTER THE CORRECT CODE TO BE ABLE TO CHANGE DEFAULT SETTINGS"

while :

do

_COUNTER=`expr $_COUNTER + 1`

echo -n "Enter the code to change the settings:"

read T_CODE

# echo $_COUNTER

if [ "$T_CODE"="$_CODE" ]; then

return 0

else

if [ "$_COUNTER" -gt 3 ]; then

echo "Sorry incorrect code entered, you cannot change the settings.." return 1

fi

fi

done

}

check_drivef() {

# перемотка ленты

mt -f /dev/$_DEVICE rewind > /dev/null 2>&1

if [ $? -ne 0 ]; then

return 1 else

return 0

fi

)

#========== main ==============

# чтение файла с параметрами

check_source

header

#отображение содержимого переменных show_settings

#уточнение у пользователя, желает ли он изменить настройки

if continue_prompt "Do you wish To Change Some Of The System Defaults" "Y"; then

# да, тогда введите имя

if get_code; then

# изменение параметров change_settings fi fi

# параметры получены, резервное копирование

if check_drive; then

echo "tape OK…."

else

echo "Cannot rewind the tape..is it in the tape drive ???"

echo "Check it out"

exit 1

fi

# что копировать

case $_TYPE in

Full|full)

BACKUP_PATH="sybase syb/support etc var bin apps use/local";;

Normal|normal)

BACKUP_PATH="etc var bin apps usr/local";;

Sybase|sybase)

BACKUP_PATH="Sybase syb/support";;

esac

# резервное копирование

cd /

echo "Now starting backup "

find $BACKUP_PATH -print | cpio -ovB -O /dev/$_DEVICE >> $_LOGFILE 2>&1

#если приведенная выше команда cpio не выполняется в системе,

#воспользуйтесь командой cpio, приведенной ниже

#find $BACKUP_PATH -print [ cpio -ovB > /dev/$_DEVICE >> $_LOGFILE 2>&1

#для получения дополнительной информации измените -ovB на -ovcC66536

if [ "$_INFORM"="yes" ]; then

echo "Backup finished check the log file" | mail admin fi

Файл backup.defaults содержит заданные по умолчанию настройки наряду с функцией continue_prompt. Ниже приводится содержимое файла.

$ pg backup.defaults

#!/bin/sh

#backup.defaults

#файл конфигурации, заданный по умолчанию, для сетевых резервных копий

#редактируете его на свой страх и риск!!

#

_CODE="comet"

_LOGFILE="/appdva/backup/log.`date +%y%m%d`"

_DEVICE="rmt0"

_INFORM="yes"

_TYPE="Full"

continue_prompt ()

#continue_prompt

#для вызова: continue_prompt "отображаемая строка"

default_answer ()

{

_STR=$1

_DEFAULT=$2

# проверка ввода корректных параметров

if [ $# -lt 1 ]; then

echo "continue_prompt: I need a string to display"

return 1

fi

while : do

echo -n "$_STR [Y.. N] [$_DEFAULT]:"

read _ANS

: ${_ANS:=$_DEFAULT]

if [ "$_ANS" = "" ]; then

case $_ANS in

Y) return 0 ;;

N) return 1 ;;

esac

fi # пользователь сделал выбор

case $_ANS in

y|Y|Yes|YES) return 0;;

n|N|No|NO) return 1;;

*) echo "Answer either Y or N, default is $_DEFAULT";;

esac

echo $_ANS

done

}

Ниже приводится поток вывода при отображении настроек, заданных по умолчанию, причем пользователя запрашивают, желает ли он изменить эти настройки:

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

Tape Device: rmt0, rmt1, rmt3

Mail Admin: yes, no

Backup Type: full, normal, Sybase

Tape Device To Be Used For This Backup [rmt0]:

Mail Admin When Done [yes]:

Backup Type [Full]: Normal

Cannot rewind the tape..is it in the tape drive ???

Check it out

 

27.3. Сценарий del.lines

О данном сценарии часто заходит речь, когда разработчики вопрошают: "Где же команда sed, выполняющая повторное удаление пустых строк?" Именно для этой цели и создан этот небольшой сценарий.

Действительно, сценарий представляет собой оболочку для потокового редактора sed. Поскольку этот процесс применяется довольно часто, разработчики заинтересованы в подобном сценарии.

Сценарии интерпретатора shell не должны быть большими. Создание сценариев целесообразно, если при автоматизации задач экономится время пользователя.

Сценарий del.lines может обрабатывать один или несколько файлов. До того, как команда sed приступит к удалению всех пустых строк, проверяется наличие каждого файла. Поток вывода команды sed с помощью символов $$ направляется во временный файл. Затем файл перемещается обратно, заменяя исходный файл.

Чтобы просмотреть все имена файлов, применяется команда shift. Цикл while выполняется до тех пор, пока имеются обрабатываемые файлы.

Введите команду del.lines -help, в результате чего отобразится немного разреженная справочная строка. Желательно создать более удобную справочную конструкцию. Сценарий имеет следующий вид:

$ pg del.lines

#!/bin/sh

#del.lines

#сценарий получает имена файлов и удаляет из них все пустые строки

TEMP_F=/tmp/del.lines.$$

usage ()

{

# usage

echo "Usage :`basename $0` file [file..]"

echo "try `basename $0` -help for more info"

exit 1

}

if [ $# -eq 0 ]; then

usage

fi

FlLES=$1

while [ $# -gt 0 ] do

echo "..$1"

case $1 in

-help) cat << MAYDAY

Use this script to delete all blank lines from a text file(s)

MAYDAY

exit 0;;

*)FILE_NAME=$1

if [ -f $1 ]; then

sed '/^$/d' $FILE_NAME > $TEMP_F

mv $TEMP_F $FILE_NAME

else

echo "`basename $0` cannot find this file : $1"

fi

shift;;

esac

done

 

27.4. Сценарий access.deny

Чтобы пользователи не регистрировались в системе при введении необходимых обновлений, можно воспользоваться методом /etc/nologin, который доступен для большинства систем. Когда в каталоге /etc создается файл nologin, обычно применяется команда touch. И никто из пользователей, кроме пользователя root, не может зарегистрироваться.

Если данная система не поддерживает метод nologin, не все потеряно — можно создать подобный метод самостоятельно. Ниже показано, как это осуществить на практике.

В файл /etc/profile помещается следующий код:

if [ -f /etc/nologin ]; then

if [ $LOGNAME != "root" ]; then

echo "Sorry $LOGNAME the system is unavailable at the moment"

exit 1

fi

fi

Теперь, если требуется запретить регистрацию для всех пользователей, за исключением пользователя root, примените команду touch для создания в каталоге /etc файла nologin и удостоверьтесь, что все пользователи имеют право читать этот файл.

touch /etc/nologin chmod 644 /etc/nologin

Если необходимо вернуться к старому порядку, удалите файл nologin следующим образом:

rm /etc/nologin

Описанная методика используется для отключения всех пользователей, кроме пользователя root. Если нужно временно отключить некоторые учетные записи, можно обратиться к файлу /etc/passwd, а в качестве первого символа в поле пароля следует указать символ *. Однако такой подход применяется редко, и если пользователь недостаточно четко выполняет все действия, можно столкнуться с проблемами при работе всей системы.

Linux располагает утилитой, с помощью которой в файл login.access вводятся имена пользователей и групп. Этот файл предназначен для предоставления доступа к системе.

Рассмотрим версию утилиты под названием deny.access. Сценарий, который выполняется из файла /etc/profile, просматривает файл lockout.user. Этот файл включает имена пользователей, в регистрации которых вы не заинтересованы. Если в файле присутствует слово "all", доступ запрещается всем пользователям, кроме пользователя root.

Ниже приводится пример файла lockout.user. Этот файл может включать строки комментария.

$ pg lockout.users

#lockout.users

#поместите в этот файл имена пользователей по вашему усмотрению

#снятие системной блокировки

#Удалите из этого файла имена пользователей, чтобы пользователи могли

#вернуться назад.

#peter находится в долговременном отпуске и вернется в следующем месяце

peter

#lulu отсутствует две недели, вернется в конце месяца

lulu

dave

pauline

Рассмотрим, как функционирует сценарий. Сначала выполняется команда trap для игнорирования сигналов. Вследствие этого пользователь не может прервать выполнение сценария. Если имеется файл lock.users, сценарий продолжает выполняться. Первым делом проверяется наличие слова "alf" Если это слово присутствует, тогда не принимаются во внимание имена всех пользователей из данного файла. Не следует применять строку комментария для устранения влияния слова "all"; этот путь не приведет к успеху. Однако можно устранить из комментария имена пользователей.

Если обнаружена запись "all", блокируются имена всех пользователей, кроме пользователя root. Чтобы удостовериться в том, что найдено точное соответствие шаблону, применяют шаблон all\> команды grep. На экран для пользователей системы выводится сообщение о том, что система в данный момент недоступна.

Основной функцией является функция get_users. Она реализует просмотр файла lockout.users, причем игнорируются все строки, начинающиеся с символа хэша. Выполняется сравнение имен и проверяется, что имя пользователя root не содержится в файле. В результате этого имя пользователя root блокируется.

Регистрационное имя пользователя, находящегося в текущий момент в системе, извлекается из переменной LOGNAME и сравнивается со значением переменной names. Переменная names сохраняет имя текущего пользователя из просматриваемого файла lockout.users. Если совпадение найдено, значение переменной LOGNAME отображается вместе с сообщением. Затем пользователь завершает работу сценария.

Этот сценарий выполнялся на нескольких машинах, которые охватывали до 40 пользователей. Во время процесса регистрации скорость выполнения сценария была довольно высока. Сценарий использовался с целью временной блокировки доступа для тех пользователей, которые отсутствовали более недели. Кроме того, доступ для отдельных пользователей блокировался ежедневно на определенное время, в течение которого обновлялись жизненно важные системы.

В файл /etc/profile следует поместить следующую строку. Эта строка может быть размешена в конце файла, тогда пользователи получат возможность просматривать это сообщение первым среди дополнительных сведений.

. /apps/bin/deny.access

Каталог /apps/bin является областью, где можно хранить все глобальные сценарии. Возможно применение другой области, однако при этом следует убедиться в том, что каждый пользователь может выполнить этот сценарий и воспользоваться каталогом, в котором он находится.

Если получено сообщение об ошибке "permission denied" ("разрешения нет"), значит, сценарий или каталог не имеют достаточного уровня разрешения.

В данном случае файл lockout.users находится в каталоге /apps/etc. Этот каталог можно изменить, поскольку ваша структура наверняка отличается от рассматриваемой. Поскольку файл является исходным, с помощью команды set можно просматривать код функции (но не фактический файл lockout.users). Если это затруднительно, примените команду unset для удаления функции после ее выполнения. Поместите команду unset непосредственно после обращения к сценарию в файл /etc/profile. Например:

unset get_users

Сценарий имеет следующий вид:

$ pg deny.access

#!/bin/sh

#deny.access

trap "" 2 3

#откорректируйте следующую строку,

#если местоположение файла LOCKOUT.USERS изменено.

LOCKOUT=/apps/etc/lockout.users

MSG="Sorry $LOGNAME, your account has been disabled, ring the administrator"

MSG2="Sorry $LOGNAME, the system ls unavailable at the moment"

check_lockout ()

#check_lockout

#проверка наличия файла, содержащего имена для блокировки

{

if [ -r $LOCKOUT ] ; then

return 0

else

return 1 fi

}

get_users ()

#get_users

#чтение файла, если содержимое LOGNAME совпадавет с именем в lockout.users

#отбросьте его!

{

while read NAMES

do

case $NAMES in

\#*);; #игнорируйте комментарии

*)

#если кто‑либо попытается блокировать root,

#в этом сценарии ему это сделать не удастся

if [ "$NAMES"="root" ]; then

break

fi

if [ "$NAMES"="$LOGNAME" ]; then

# сообщение об отказе в регистрации

echo $MSG

sleep 2

exit 1

else

# нет совпадения, следующая итерация

continue

fi;;

esac

done < $LOCKOUT

}

if check_lockout; then

if grep 'all\>' $LOCKOUT >/dev/null 2>&1

then

#сначала проверьте, имеется ли слово "all". Если это слово

#присутствует, все, кроме root, должны держаться подальше

if [ "$LOGNAME" != "root" ]; then

echo $MSG2

sleep 2

exit 2

fi

fi

# обработка информации об обычных пользователях

get_users

fi

 

27.5. Сценарий logroll

Некоторые системные журнальные файлы увеличиваются довольно быстро. Становится затруднительным вручную уточнять размеры журнальных файлов и выполнять прокрутку определенного журнала (обычно, с помощью отметки даты). Поэтому назрела необходимость создания сценария для автоматизации этой процедуры. Сценарий выполняется с помощью утилиты cron, и если какой‑либо журнальный файл достигает определенного размера, осуществляется прокрутка данного журнала и создание нового журнального файла.

Этот сценарий может быть легко обновлен для работы с иными журнальными файлами. Например, при обработке системных журнальных файлов можно применить другой сценарий, который выполняется еженедельно и усекает журнальные файлы. Если необходимо просмотреть более ранние сообщения, нужно проверить резервную копию; при работе в 16–недельном цикле это нетрудно.

Ограничение размера устанавливается с помощью переменной BLOCKLIMIT. Эта переменная указывает размер блока, который в данном случае равен восьми и соответствует 4 Кб, При необходимости можно установить большее значение. Информация обо всех журнальных файлах, подлежащих проверке, хранится с помощью переменной logs.

Затем с помощью этой переменной и цикла for выполняется проверка каждого журнального файла. Применяя команду du, можно оценить размер журнального файла. Если размер файла превышает значение blocklimit, журнальный файл копируется и с добавлением временной метки присоединяется к этому файлу. Затем исходный файл обнуляется, и изменяются права владения на группу файлов.

Сценарий выполняется с помощью утилиты cron два раза в неделю; при этом создается резервная копия файла с указанием временной метки. Поэтому при возникновении проблем можно быстро отследить выполненные действия.

$ pg logroll

#!/bin/sh

#logroll

#усечение журнальных файлов, размеры которых более MARK

#может использовать и для почтовых ящиков?

#максимальный размер журнального файла 4096 к

BLOCK_LIMIT=8

MYDATE=`date +%d%m`

# список журнальных файлов для проверки…ваш список может быть другим!

LOGS="/var/spool/audlog /var/spool/networks/netlog /etc/dns/named_log"

for LOG_FILE in $LOGS

do

if [ -f $LOG_FILE ]; then.

# определение размера блока

F_SIZE=`du -a $LOG_FILE | cut -f1`

else

echo "`basename $0` cannot find $LOG_FILE" >&2

#можно выйти здесь, но следует убедиться, что проверены все

#журнальные файлы

continue

fi

if [ "$F_SIZE" -gt "$BLOCK_LIMIT" ]; then

#копирование журнального файла и присоединение к нему даты в формате ddmm

cp $LOG_FILE $LOG_FILE$MYDATE

#создание нового пустого журнального файла

>$LOG_FILE

chgrp admin $LOG_FILE$MYDATE

fi

done

 

27.6. Сценарий nfsdown

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

Если везде смонтированы удаленные каталоги, не следует рассчитывать на то, что процесс демонтирования nfs будет выполнен в ходе перезагрузки. Желательно выполнять все вручную; кроме того, такой подход экономит время.

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

Сценарий содержит список компьютеров, на которых находятся монтировки nfs. Этот список обрабатывается с помощью цикла for. Во время обработки с помощью команды df для каждого хоста запускается утилита grep. Смонтированные каталоги nfs имеют вид:

machine: remote_directory

Данная строка присваивается переменной nfs_machine. Затем эта переменная применяется при выполнении команды unmount. Соответствующий сценарий имеет вид:

$ pg nfsdown

#!/bin/sh

# nfsdown

LIST="methalpha accounts warehouse dwaggs"

for LOOP in $LIST

do

NFS_MACHINE=`df -k | grep $LOOP | awk '{print $1}'`

if [ "$NFS_MACHINE" != "" ]; then

umount $LOOP

fi

done

 

27.7. Заключение

Рассмотренные в этой главе сценарии в течение длительного времени используются автором книги. Как уже упоминалось, сценарии не должны быть объемными и сложными, поскольку они создаются с целью экономии рабочего времени пользователя.

 

ГЛАВА 28

 

Сценарии уровня выполнения

Если при загрузке системы вам нужно автоматически запустить приложение, службу или сценарий либо корректно завершить их работу при перезапуске системы, то необходимо создать сценарий уровня выполнения. Почти все варианты системы Linux, а также некоторые системы UNIX в настоящее время имеют каталоги конфигурации уровня выполнения, которые основаны на System V.

Поскольку большая часть систем включает конфигурацию этого типа, именно он и рассматривается далее. Если вы не располагаете каталогами уровня выполнения, не беспокойтесь. Приложения можно запускать в автоматическом режиме; этот метод также обсуждается в данной главе.

В главе рассматриваются следующие темы:

   • уровни выполнения;

   • способы создания сценариев rc.scripts;

   • методы внедрения сценариев rc.scripts на различных уровнях выполнения;

   • запуск приложений с помощью файла inittab.

Благодаря созданию сценариев уровня выполнения обеспечивается повышенная степень гибкости при управлении системой. Для запуска или останова приложения на определенном уровне выполнения нужно инсталлировать сценарий уровня выполнения (его еще называют rc.script).

Все сценарии, которые, запускают и прекращают выполнение приложения, и в названии которых имеются ключевые слова "start" или "stop", обычно относятся к сценариям класса rc.script. Обратите внимание на то, что именно пользователь определяет, является ли реализуемый сценарий сценарием типа rc.script. В задачу этого сценария входит успешный запуск и прекращение функционирования какой‑либо службы.

Методика создания каталогов конфигурации уровня выполнения позволяет автоматизировать работу сценариев rc.scripts только при изменении уровня выполнения. Однако нельзя определить, запущены или остановлены все необходимые службы на уровне выполнения. Эта часть работы должна выполняться shell–программистом.

Уровни выполнения можно настраивать в соответствии с действительно выполняемыми службами, но данная тема в книге не рассматривается.

 

28.1. Определение наличия каталогов уровня выполнения

Каталоги, где хранятся сценарии rc.scripts (здесь фактически речь идет о ссылках, которые мы рассмотрим далее), имеют следующий вид:

/etc/rcN.d

или

/etc/rc.d/rcN.d

где N — число. Обычно это число равно семи, поскольку каталоги rcN. d нумеруются от 0 до 6. Однако в системе можно иметь несколько дополнительных каталогов типа rcS.d. Количество каталогов не столь важно; все рассматриваемые каталоги перечислены ниже.

$ pwd

/etc

$ ls -l

drwxr‑xr‑x 2 root sys 1024 Dec 22 1996 rc0.d
drwxr‑xr‑x 2 root sys 1024 Dec 22 1996 rc1.d
drwxr‑xr‑x 2 root sys 1024 Dec 22 1996 rc2.d
drwxr‑xr‑x 2 root sys 1024 Dec 22 1996 rc3.d
drwxr‑xr‑x 2 root sys 1024 Dec 22 1996 rc4.d
drwxr‑xr‑x 2 root sys 1024 Dec 22 1996 rc5.d
drwxr‑xr‑x 2 root sys 1024 Dec 22 1996 rc6.d
drwxr‑xr‑x 2 root sys 1024 Dec 22 1996 rcS.d

В Linux…

$ pwd

/etc/rc.d

$ ls

init.d rc.local rc0.d rc2.d rc4.d rc6.d

rc rc.sysinit rc1.d rc3.d rc5.d

Если команда cd применяется в одном из каталогов rcN.d, можно просмотреть и другие сценарии rc.scripts, связанные с этими каталогами.

$ pwd

/etc/rc.d/rc2.d

$ ls -1

lrwxrwxrwx 1 root root 16 Dec 3 15:16 K87ypbind -> ../init.d/yd
lrwxrwxrwx 1 root root 17 Dec 3 15:10 K89portmap -> ../init.d/p
lrwxrwxrwx 1 root root 17 Dec 3 15:07 S01kerneld -> ../init.d/d

 

28.2. Уточнение текущего уровня выполнения

В этой главе не рассматриваются вопросы системного администрирования, однако shell–программист должен знать не только принципы функционирования сценариев rc.scripts, но также принципы их совмещения с каталогами конфигурации уровня выполнения. Для уточнения уровня выполнения примените команду:

$ who -r

run‑level 4 Apr 22 13:26 4 0 3

Число, расположенное после слов "run‑level" является текущим уровнем выполнения. Следующие за ним данные определяют время выполнения последней перезагрузки системы.

В Linux…

$ runlevel 2 3

В первом столбце указан уровень, на котором система находилась на предварительном этапе, а во втором столбце — текущий уровень, который в данном случае равен 3.

 

28.3. Ускорение работы с помощью файла inittab

Каталог уровня выполнения состоит из набора сценариев, более совершенных, чем службы. Слово "services" в этом контексте означает и демон, и приложение, и серверы, и подсистемы или процессы сценария. Во время загрузки системы вызывается процесс init (этот процесс является родоначальником всех остальных процессов). Одной из задач упомянутого процесса является определение запускаемых служб, а также определение уровня выполнения, заданного по умолчанию. Эти сведения можно получить, просматривая текстовый файл конфигурации под названием inittab, размещенный в каталоге /etc. Процесс init также использует этот файл для получения указаний по поводу загрузки определенных процессов. Если необходимо изменить этот файл, сначала создайте резервную копию. В случае повреждения файла или возникновения ошибок, приводящих к "деградации" системы, система не будет загружаться обычным образом; вам придется загружаться в однопользовательском режиме и устранять повреждения в файле.

Файл inittab включает поля, имеющие весьма лимитированный формат. Формат файла будет следующий:

id:rstart:action:process

Поле id имеет уникальное название, которое идентифицирует запись процесса,

Поле rstart содержит число, которое указывает, на каком уровне выполнения запускается процесс.

Поле action указывает процессу init, как рассматривать текущий процесс. Существует большое количество названий для поля action, но наиболее распространенными являются wait и respawn. Название wait означает, что начавшийся процесс ожидает завершения. Название respawn означает, что процесс начинается даже в том случае, если он еще не существует. Если же существует, то запускается заново в тот момент, когда он уже завершается.

Поле process содержит действительную команду для выполнения. Ниже приводится фрагмент файла inittab.

$ pg /etc/inittab

id:3:initdefault:

# Инициализация системы.

si::sysinit:/etc/rc.d/rc.sysinit

уровень выполнения 0 10:0:wait:/etc/rc.d/rc 0

уровень выполнения 1 11:1:wait:/etc/rc.d/rc 1

уровень выполнения 2 12:2:wait:/etc/rc.d/rc 2

уровень выполнения 3 13:3:wait:/etc/rc.d/rc 3

уровень выполнения 4 14:4:wait:/etc/rc.d/rc 4

уровень выполнения 5 15:5:wait:/etc/rc.d/rc 5

уровень выполнения 6 16:6:wait:/etc/rc.d/rc 6

Выполнение gettys на стандартных уровнях выполнения

1:12345:respawn:/sbin/mingetty tty1

2:2345:respawn:/sbin/mingetty tty2

3:2345:respawn:/sbin/mingetty tty3

4:234 5:respawn:/sbin/mingetty tty4

5:234 5:respawn:/sbin/mingetty tty0

6:2345:respawn:/sbin/mingetty ttyS1 vt100

Первая строка файла описывает уровень выполнения системы, заданный по умолчанию; ниже приводится уровень выполнения 3, который не является чем‑либо необычным.

Строки, которые начинаются числами 10—16, определяют запуск или прекращают выполнение сценариев уровней выполнения для определенных уровней выполнения. Например, рассмотрим следующую строку:

15:5:wait:/etc/rc.d/rc 5

В строке содержится следующая информация: если пользователь находится на уровне выполнения 5, сценарий /etc/rc.d/rc запускается с параметром 5. Это означает, что сценарий /etc/rc.d/rc выполняет все сценарии в каталоге /etc/rc.d/rc/rc5.d.

Последняя строка файла — уровни выполнения 2, 3, 4 и 5 -cвидетельствует о том, что процесс заново возрождается. То есть, процесс никогда не уничтожится (ну, по крайней мере, в течение одной секунды). Непрерывно отвергается процесс mingetty для последовательного порта tty$1. В данном случае в роли параметра используется ID терминала, который имеет значение vt100.

 

28.4. Переходим к уровням выполнения

 

Одной из последних задач процесса init, которая реализуется перед тем, как система "полностью запустится", является выполнение всех сценариев для уровня выполнения, заданного по умолчанию. Файл, осуществляющий эту задачу, называется либо /etc/rc.d/rc, либо /etc/rc.init. Роль этого сценария заключается в первоначальном уничтожении процессов для этого уровня, а затем — в установке процессов данного уровня.

Как процесс определяет, какие службы запускаются или прекращают выполнение? Файл rc или rc.init выполняет функции цикла for при обработке каждого сценария rc.script. Каждый сценарий rc.script запускается в каталоге rc3.d с помощью опции K, и ему передается параметр "stop". Затем аналогичный процесс поддерживается для всех сценариев rc.scripts, которые запускаются с помощью опции s, и им передаются параметры "start". Конечно, подобный процесс поддерживается при обращении к измененному уровню выполнения. Но, в отличие от каталога rc3.d, в данном случае обрабатывается каталог rcN.d, благодаря чему изменяется уровень выполнения N.

Сценарии, находящиеся в каталоге rcN.d, представляют собой только ссылки — фактические сценарии вызываются в другом месте. Эти сценарии располагаются в каталоге под названием /usr/sbin/init.d или /etc/init.d.

В Linux…

/etc/rc.d/init.d

В этом каталоге хранятся несколько сценариев, которые могут запускать иди прекращать функционирование служб. Имена этих сценариев формируются по системе rc.<что он делает>, где rc означает run command или run control. Некоторые системные администраторы называют эти сценарии "реально критическими" (really crucial). Ниже приводится листинг подобного файла.

$ ls

rc.localfs rc.halt rc.reboot rc.syslogd rc.daemon

Общий формат вызова сценариев rc.scripts будет следующим:

rename stop -oстанов службы rc.name start — запуск службы

Необязательными вызовами являются вызовы перезапуска и состояния. Любой другой вызов появляется в ответ на сообщение о применении, в котором содержится методика вызова сценария rc.script. Следует отметить, что эти сценарии можно вызывать вручную.

Итак, вы уже изучили, какие функции выполняет сценарий при вызове. Следующий этап — помещение сценариев в соответствующие каталоги rcN.d. Но сначала рассмотрим систему уровней выполнения.

 

28.4.1. Различные уровни выполнения

Существует семь уровней выполнения (табл. 28.1). Различные системы имеют на некоторых уровнях небольшие отличия.

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

Таблица 28.1. Функции различных уровней выполнения

Уровень выполнения 0 Прекращает и останавливает целую систему
Уровень выполнения I Отдельный пользователь или режим администрирования
Уровень выполнения 2 Многопользовательский режим; запускаются некоторые
сетевые службы. Ряд систем использует этот уровень как уровень выполнения в обычном режиме функционирования вместо уровня выполнения 3
Уровень выполнения 3 Обычный режим функционирования, применяется для всех сетевых служб
Уровень выполнения 4 Уровень определенного пользователя; применяйте этот уровень для настройки при выполнении
Уровень выполнения 5 Этот уровень имеет некоторые вариации в виде заданного по умолчанию режима X‑windows; в других случаях этот уровень применяется для перевода системы в режим поддержки
Уровень выполнения 6 Перезагрузка

 

28.4.2. Формат сценария уровня выполнения

Сценарии в каталогах rcN.d представляют собой все символические ссылки, которые сохраняют дублирование сценариев на нулевом уровне. Формат этих ссылок:

Snn.имя_сценария

или

Кnn.имя_сценария

где

S Означает запуск процесса
K Означает уничтожение процесса
nn Является двузначным числом от 00 до 99, хотя некоторые системы характеризуются трехзначными числами от 000 до 999. При установлении ссылок на различные каталоги сохраняйте то же самое число. Например, если служба запускается в каталоге rc3.d и сценарий называется S45.myscript, то при запуске этой службы в каталоге rc2.d нужно убедиться, что сценарий также называется S45.myscript.
имя сценария Является названием сценария, зависящим от типа системы. Может находиться в одном из файлов:
/usr/sbin/init.d /etc/rc.d /etc/init.d

Когда процесс init требует вызова сценариев rc.scripts, выполняется процесс уничтожения, начиная от самого большего и завершая самым меньшим числом К, т. е. К23.myscript K12.named. Запуск выполняется в диапазоне от самого меньшего до самого большего значения. Если вы работаете в системе Linux, числа К вызываются от самого большего до самого меньшего числа.

 

28.4.3. Инсталляция сценария уровня выполнения

Чтобы инсталлировать собственный сценарий rc.script, следует выполнить следующее:

   • написать сценарий, который действительно удовлетворяет стандартам вызова;

   • удостовериться, что сценарий действительно запускает или останавливает необходимую службу;

   • разместить сценарий (в зависимости от системы( в каталоге /etc/init.d, /usr/sbin/init.d или в каталоге /etc/rc.d;

   • cоздать ссылки во всех подходящих каталогах rcN.d, используя соответствующее соглашение о наименовании.

Ниже приводится сценарий, который запускает и прекращает выполнение приложения под названием rc.audit- Эта служба запускается на уровнях выполнения 3, 5 и 4 и уничтожается на уровнях выполнения 6, 2 и 1. При просмотре некоторых записей в каталогах rcN.d число 35 является зарезервированным, поэтому оно применяется в данном случае. Действительно, нет причин прекращать функционирование сценария, поэтому применяется число, которое уже использовалось.

Рассмотрим этот сценарий. Как можно заметить, простая конструкция case выполняет перехват параметров stop и start.

$ pg rc.audit

#!/bin/sh

#rc.audit start | stop

#сценарий запускает или прекращает выполнение

#контролирующего приложения zeega

#

case "$1" in

start)

echo -n "Starting the audit system…."

/apps/audit/audlcp -a -p 12

echo

touch /var/lock/subsys/rc.audit

;;

stop)

echo -n "Stopping the audit system…."

/apps/audit/auddown -k0

echo

rm -f /var/lock/subsys/rc.audit

;;

restart)

$0 stop

$0 start

;;

*)

echo "To call properly..Usage: $0 {start | stop | restart}"

exit 1

;;

esac

exit 0

В Limix…

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

Опция start вызывает контрольный процесс, который запускает действительную систему контроля, а опция stop вызывает сценарий, останавливающий систему контроля. Конечно, перед помещением сценария в каталог init.d его следует проверить.

$ rc.audit

То call properly..Usage:./rc.audit {start|stop|restart}

$ rc.audit start

Starting the audit system….

Предположим, что сценарий проверен. Запуск и прекращение функционирования службы контроля реализуется без затруднений. Установим связь сценария с нужными каталогами выполнения.

В данной системе каталоги rcN.d помешены в файл /etc/rc.d, а сценарии rc.scripts помещены в файл /etc/rc.d/init.d. Измените пути, если это необходимо.

Внимательно приступайте к первоначальному запуску сценария; не забывайте, что запуск сценариев начинается с указания опции s.

$ pwd

/etc/rc.d/rc3.d

$ ln -s ../init.d/rc.audit S35rc.audit

$ ls -1

lrwxrwxrwx 1 root root 27 May 8 14:37 S35rc.audit -> ../init.d/rc.audit

Теперь создается ссылка. Поток вывода команды ls -l, который показывает ссылку, направляется в файл /etc/init.d/rc.audit. Как часть команды ссылки, поддерживается путь ко всему каталогу, но это не обязательно. Теперь необходимо применить команду cd для последовательного перехода во все каталоги, где нужно запустить службу (в данном случае rc4.d и rc5.d), и выполнить в них аналогичные действия. Для уничтожения сценариев примените следующие команды:

$ pwd

/etc/rc.d/rc6.d

$ ln -s ../init.d/rc.audit K35rc.audit

$ ls -l

lrwxrwxrwx 1 root root 27 May 8 14:43 K35rc.audit -> ../init.d/rc.audit

Аналогичную процедуру можно реализовать для других каталогов, где нужно остановить выполнение службы контроля. Теперь при перезагрузке системы служба контроля прекращает выполняться. Это происходит и в том случае, когда значения уровней выполнения изменяются на 2 или 1. Служба контроля запускается, если значение уровня выполнения изменяется на 4 или 5.

 

28.5. Использование файла inittab для запуска приложений

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

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

$ cp /etc/inittab /etc/inittab.bak

Отредактируем файл inittab. В конец файла добавим следующую запись.

#сценарий проверки диска, рассмотрим, не повреждены ли какие–либо зеркальные образы.

rc.diskchecker:3:once:/usr/local/etc/rc.diskchecker > /dev/console 2>&1

Теперь следует сохранить файл и выйти из редактора.

Вышеприведенная запись означает следующее: Rc.diskchecker является уникальным ID на уровне выполнения 3. Выполните этот процесс один раз. Сценарий находится в файле /usr/hcal/etc/rc.diskchecker, весь поток вывода направляется на консоль.

 

28.6. Другие методы, применяемые для запуска и останова служб

Если вы не желаете применять файл /etc/inittab, существует другая возможность запустить службу. Большая часть систем включает файл rc.local, который помещается в каталоге /etc либо рядом с ним. Этот файл сценария закрывается после запуска файла inittab и сценария rc.scripts. В файл rc.local можно ввести все необходимые команды или добавить запись для вызова удобного вам сценария запуска.

Некоторые системы также поддерживают сценарный файл под названием shutdown, который находится в каталоге /bin (хотя довольно часто этот файл может располагаться в каталоге /usr/sbin). Воспользуйтесь этим файлом для завершения выполнения служб, используя команду завершения работы системы.

 

28.7. Заключение

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

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

 

ГЛАВА 29

 

Сценарии cgi

В настоящее время, когда практически на каждом ПК установлен Web–сервер, глава, посвященная сценариям cgi, органически вписывается в книгу по shell–программированию.

В главе будут рассмотрены следующие темы:

   • базовые сценарии cgi;

   • использование SSI;

   • метод get;

   • метод post;

   • создание интерактивного сценария;

   • сценарий cgi, автоматически обновляющий Web–страницу.

Для установки Web–сервера вовсе необязательно организовывать сеть; этот сервер может быть запущен на локальном компьютере. Изначально предполагается, что у вас установлен Web–сервер (Apache, Cem и т. п.) и броузер, используемый для просмотра Web–страниц (Netscape, Internet Explorer и т. п.). Помимо этого, сервер должен поддерживать cgi. По умолчанию поддержка cgi отключена путем добавления знаков комментариев в определенные строки сценария. Дополнительные сведения по этому вопросу можно найти в последующих разделах этой главы.

Вопросы установки и настройки Web–сервера выходят за рамки данной книги, хотя установка и запуск Web–сервера занимают не более 20 минут. Примеры, приведенные в этой главе, были выполнены с помощью Web–сервера Apache. В качестве Web–броузера использовался броузер Internet Explorer.

В главе не рассматриваются подробно особенности HTML или Web, поскольку в настоящее время существует множество книг, посвященных этим вопросам. Обсуждение HTML потребовало бы написания нескольких дополнительных глав.

 

29.1. Определение Web–страницы

Web–страница (или Web–документ) состоит из тегов HTML. Когда броузер загружает Web–страницу, тега определяют способ отображения этой страницы на экране. Web–страница может состоять из многих элементов, включая ссылки (которые позволяют связывать между собой различные страницы), цвета, выделения, шрифты разных размеров, линии и таблицы. В состав Web–страницы могут также включаться картинки и звуковые фрагменты.

Существует два типа Web–страниц: динамические и статические. Статические страницы могут применяться только для отображения информации либо, возможно, для выполнения загрузки файлов. Динамические страницы являются интерактивными: они

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

Для поддержки информационного обмена между сервером и сценариями требуется протокол Common Gateway Interface (Интерфейс общего шлюза), который обычно именуется cgi.

 

29.2. Протокол cgi

Аббревиатура cgi обозначает спецификацию, которая задает для получающих информацию сценариев способ обмена данными с сервером. Подобные сценарии (или сценарии cgi) могут быть созданы с помощью любого языка написания сценариев. Наиболее популярным является язык Perl, хотя с этой целью могут применяться и обычные shell–сценарии, как вы убедитесь далее.

Рис. 29.1. Броузер и сервер, использующие интерфейс cgi для обмена информацией

 

29.3. Подключение к Web–серверу

Для подключения к Web–серверу используется URL (Uniform Resource Locator — унифицированный указатель ресурсов). Указатель URL содержит два типа информации:

протокол адрес и данные

Протоколом может быть протокол http, ftp, mailto, file, telnet и news. В этой главе будет рассматриваться только http, протокол передачи гипертекста (hypertext transfer protocol).

В качестве адреса обычно выступает имя DNS или хост–имя сервера, хотя может применяться IP–адрес. Можно использовать и другую информацию, например фактическое имя пути к файлу, к которому осуществляется доступ.

Все подключения реализуются с помощью протокола TCP. При этом по умолчанию используется порт 80.

Если на локальном компьютере установлен Web–сервер, а основная HTML–страница называется index.html, можно воспользоваться следующим URL:

http://localhost/index.html

Вообще говоря, файл index.html — это файл, загружаемый по умолчанию. (Имя файла, загружаемого по умолчанию, можно изменить с помощью файлов конфигурации сервера.) Следовательно, в этом случае можно ввести такой URL:

http://localhost/

 

29.4. Сценарии cgi и HTM

 

Когда броузер генерирует запрос на загрузку страницы, Web–сервер задается в виде входящего URL. Если в качестве части URL–пути указывается cgi‑bin, сервер открывает соединение, которое обычно реализует перенаправление к запрашиваемому cgi–сценарию. Входной и выходной поток сценария cgi отсылаются с помощью этого перенаправления. Если сценарий cgi используется для отображения форматированной Web–страницы, он должен включать теги HTML. Благодаря этому отображаемая страница может распознаваться Web–сервером, хотя при этом от пользователя потребуются некоторые познания в области HTML. Этот документ может отсылаться Web–сервером броузеру с целью отображения для пользователя. В табл. 29.1 представлены некоторые полезные теги HTML.

Таблица 29.1. Основные теги HTML, применяемые для создания страниц

<HTML></HTML> Теги открытия и закрытия документа
<HEAD></HEAD> Открытие и закрытие информационной области
<TITLE></TITLE> Открытие и закрытие заголовка
<BODY></BODY> Открытие и закрытие отображаемой страницы
<Hn></Hn> <P></P> Заголовочный шрифт, увеличение размера шрифта Начало и конец абзаца
<BR> Разбиение строки
<HR> Горизонтальная линия
<PRE></PRE> Открытие и закрытие предварительно отформатированного текста, всех символов табуляции, всех сохраненных строк
<B></B> Полужирный стиль символов
<!></!> Курсив
<OL></OL> Сортированные списки
<A HREF=url>link</A> Гипертекстовая или горячая ссылка на страницу или URL
<FORM></FORM> Определение формы
METHOD Метод post или get
ACTION Адрес
<INPUT…> Запись данных
NAME Имя переменной
SIZE Ширина текстового поля, заданная в символах
TYPE Флажок, переключатель, кнопка восстановления или фиксации
<SELECT…> Разворачивающееся меню
NAME Имя переменной
SIZE Количество отображаемых элементов списка
<OPTION VALUE> Возврат выбранной опции переменной NAME
</SELECT> Закрытие выбранного списка

 

29.4.1. Базовый сценарий cgi

Все сценарии обычно находятся в каталоге cgi‑bin Web–сервера, хотя подобное размещение может быть изменено. Для изменения размещения сценариев и подключения сервера cgi следует обратиться к файлам конфигурации srm.conf и разделу ScriptAlias. Все сценарии должны иметь расширение .cgi. Все документы обычно размещаются в каталоге html либо htdocs и имеют расширение .html. Для всех сценариев требуется установить следующие права доступа:

chmod 755 script.cgi

По умолчанию любые подключения к Web–странице обычно осуществляются от имени пользователя nobody, хотя это можно изменить с помощью файла конфигурации httpd.conf. Несмотря на то, что в этой главе не рассматриваются вопросы настройки Web, некоторые моменты все же стоит отметить. В частности, неплохо было бы проверить, отключено ли поле пароля "nobody". Если это так, запрещается подключение для произвольных пользователей, в то время как пользователь nobody физически подключен к терминалу. Для отключения пароля пользователя nobody в соответствующее поле пароля просто вставьте звездочку (файл пароля /etc/passwd).

Если какой‑либо из сценариев не функционирует, первым делом нужно просмотреть журнальные файлы ошибок. В этих файлах содержатся четкие описания всех возникших ошибок. Если применяется сервер apache, журнальные файлы обычно находятся в каталоге /etc/httpd/logs либо /usr/local/apache/logs, в зависимости от того, в каком месте системы устанавливается Web–сервер. Сценарии могут быть также протестированы путем выполнения их запуска из командной строки. Конечно, в этом случае вы получите только текстовый вывод, но он окажет вам помощь при дальнейшей отладке.

А теперь приступим к созданию сценария cgi. Введите указанный ниже текст в файл, назовите его test.cgi и сохраните в каталоге cgi‑bin. He забудьте установить для сценария права доступа 755.

$ pg firstpage.cgi

#!/bin/sh

#firstpage.cgi

#отображение текстовой страницы

echo "Content‑type: text/html"

echo ""

echo ""

echo "

THIS IS MY FIRST CGI PAGE

"

echo "


"

echo "

STAND‑BY TO STAHD‑TO!

"

echo ""

В первой строке (как вы уже, наверное, знаете) указывается местоположение интерпретатора shell. Первая строка, содержащая команду echo, сообщает серверу о том, что это заголовок MIME; вторая команда echo сообщает о новой строке. Вывод сценариев cgi не будет осуществляться, если не указана новая строка после заголовка MIME.

На этом этапе отображается начальный тег , информирующий броузер о том, что весь документ представлен в формате HTML. При этом могут отображаться различные символьные шрифты, размеры которых варьируются от наибольшего, <Н1>, до наименьшего — <Нn>. Обычно шрифт наименьшего размера, который хорошо различим, задается тегом

. Для придания красивого внешнего вида

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

для определения размера шрифта, и тег
— для центрирования текста "Stand‑By To Stand‑To". Последняя строка завершается тегом .

Если вы забудете указать какие‑либо закрывающие теги, не беспокойтесь — вы их вскоре обнаружите, поскольку при попытке загрузки в окно броузера подобного документа открывающие теги, для которых отсутствуют закрывающие, будут отображены на экране.

Теперь для отображения документа введите URL:

http://ваш_cepвep/cgi‑bin/firstpage.cgi

Вместо параметра ваш_сервер подставляется фактическое имя сервера.

Если вы работаете в сети, и при этом на экране отображается сообщение "DNS lookup failure" ("Сбой при поиске DNS"), это означает, что броузер, возможно, пытается подключиться к Internet для осуществления поиска заданной страницы. Измените параметры настройки броузера, позволяющие обойти proxy–сервер при обращении к локальным компьютерам и перезагрузите броузер.

На рис. 29.2 демонстрируется внешний вид Web–страницы.

Рис. 29.2. Результат выполнения сценария firstpage.cgi

 

29.4.2. Отображение вывода команды интерпретатора shell

Теперь поместим команду интерпретатора shell в сценарий, при этом вывод команды будет отображен в документе HTML.

Вы можете увидеть, сколько пользователей зарегистрировано на данный момент времени. Выполните команду who и отфильтруйте ее выводе помощью команды wc.

В результате отобразится количество зарегистрированных пользователей. Также выводится значение даты. Соответствующий сценарий имеет вид:

$ pg pagetwo.cgi

#!/bin/sh

#pagetwo.cgi

#отображение страницы с помощью вывода команды Unix

MYDATE=`date + %А" "%d" "%B" "%Y`

USERS=`who |wc -l`

echo "Content‑type: text/html"

echo ""

echo ""

echo "

THIS ls MY SECOND CGI PAGE

"

echo "


"

echo "

$MYDATE

"

echo " Total amount of users on to‑day ls :$USERS"

echo "

"                             

if [ "$USERS" — lt 10 ]; then

echo " It must be early or it ls dinner time"

echo " because there ain't many users logged on"

fi

echo "

"

echo ""

В начале сценария считывается информация о дате и текущих пользователях. Дата отображается в центральной части страницы. Также отображается значение переменной' users. Конструкция if используется для определения, является ли число зарегистрированных пользователей меньшим десяти; если это условие выполняется, отображается сообщение "It must be early or it's dinner time".

Тег

 применяется для сохранения опций форматирования, состоящих из служебных символов и символов табуляции. Обычно тег 
 используется для отображения вывода системных команд, таких как df, либо списка файлов, либо нескольких конструкций echo.                             

В данном случае вовсе не обязательно применять тег

, однако автор специально упомянул этот тег на ранней стадии для того, чтобы пользователь уже сейчас сознательно использовал его для разработки собственных Web–страниц. Для отображения документа введите следующий адрес:                             

http://ваш_cepвep/cgi‑bin/pagetwo.cgi

Здесь вместо параметра ваш сервер подставляется фактическое имя сервера. На рис. 29.3 показан внешний вид этой Web–страницы.

Рис. 29.3. Результат выполнения сценария pagetwo.cgi

 

29.4.3. Использование SSI

Использование сценариев cgi, открывающих Web–страницы с целью отображения небольшого количества сведений, не всегда является оправданным. Например, была отображена дата, но также был создан сценарий cgi, который тоже отображает дату. Не лучше ли было бы внедрить сценарий cgi в документ HTML таким образом, чтобы вывод сценария отображался на обычной странице? Это вполне возможно, и именно такую методику мы рассмотрим в дальнейшем.

Для внедрения сценариев cgi в документы можно воспользоваться технологией SSI (Server Side Includes — Включения со стороны сервера). При отображении документа происходит замена команды SSI результатом выполнения данной команды или сценария. При этом также экспортируются дополнительные переменные среды, содержащие сведения об установленном сервере и командах.

Для активизации возможностей SSI, обеспечивающих просмотр сервером команд SSI внутри документов, следует убрать комментарии в соответствующих строках файлов конфигурации. В случае с сервером Apache используются следующие строки:

Addhandler server‑passed.shtml

Addtype text/html shtml

Для перезапуска сервера введите команду kill -1, в результате чего сервер повторно считает конфигурационные файлы. Документы, для которых применяется SSI, используют расширение файла shtml вместо расширения html.

 

29.4.4. Счетчик количества посещений

Создадим документ, в котором отображается счетчик количества посещений. Счетчик будет выдавать сообщение типа "you are the nth visitor to this site" ("вы являетесь n–м посетителем этого сайта"). Можно также отображать дату последнего изменения страницы.

Не забудьте поместить сценарий в каталог cgi‑bin; вызовите его путем ввода hitcount.cgi.

$ pg hitcount.cgi

#!/bin/sh

#hitcount.cgi

#счетчик попыток доступа к страницам для html

#файл счетчика должен иметь атрибуты

counter=../cgi‑bin/counter

chmod 666 $counter

echo "Content‑Type: text/html"

echo ""

read access < $counter

access=`expr $access + 1`

echo $access

echo $access >$counter

Как видно из приведенного кода, сценарий считывает файл ../cgi‑bin/counter, присваивает его переменной access, добавляет к нему единицу, затем записывает результат обратно в файл /cgi‑bin/counter.

Теперь создадим файл counter. Все, что требуется в данном случае, — поместить в этот файл начальный номер; в качестве начального номера будет использована единица. Итак, создайте файл counter, введите в него 1, затем сохраните файл и выйдите из него.

Поскольку этот файл будет использоваться любым пользователем, необходимо присвоить ему права владельца, группы и других пользователей.

$ chmod 666 counter

Теперь осталось создать файл с расширением .shtml и поместить его в корневой каталог Web, где обычно находятся другие документы HTML. Файл также может находиться в каталоге htdocs или html. Ниже приводится образец этого файла; не забывайте присваивать ему расширение .shtml.

$ pg main.shtml

Last modified:


THE MAY DAY OPERATIONS CENTER

Stand‑by to Stand‑to


This page has been visited times


Последняя изменяемая переменная, также как и другие переменные, экспортируются с помощью SSI. Обратитесь к Web–узлу apache (www.apache.org) для получения полного описания всех дополнительных переменных, которые были экспортированы с помощью SSI.

Посмотрите на команду SSI:

This page has been visited times

Общий формат команды:

В нашем случае для запуска cgi–сценария hitcount применяются следующие значения параметров:

   • команда — exec,

   • аргумент -cgi,

   • "значение" — имя вызываемого сценария.

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

Если требуется изменить страницу, заданную по умолчанию, отредактируйте файл srm.conf. При этом обеспечивается доступ к следующей записи:

DirectorуIndex

В данной строке находится имя файла index.html. Измените это имя для новой страницы, заданной по умолчанию. Не забудьте закрыть и перезапустить Web–сервер, чтобы изменения возымели эффект.

Для вызова сценария введите URL:

http: //<имя_сервера>/main.shtml

или

http://<имя_сервера>

если это страница, заданная по умолчанию.

На рис. 29.4 показан пример страницы, содержащей счетчик посещений; для просмотра приращения счетчика достаточно просто обновить страницу. Обратите внимание, каким образом отображается значение переменной last_modified.

Конечно, можно каждый день сбрасывать значение счетчика. Для этого нужно воспользоваться записью одиночной команды cron, которая отправляет в файл число 1.

Рис. 29.4. Страница HTML с простым счетчиком посещений

 

29.4.5. Вывод на печать текущих настроек Web–среды с помощью ссылки

При выполнении сценария cgi какое‑то количество переменных среды становится незадействованным. Для просмотра значений большинства переменных используется команда env или set. Давайте создадим ссылку на основе файла main.shtml для вызова сценария, отображающего значения этих переменных. Ниже приведен тег, HTML, задающий такую ссылку:

<А HREF = "/cgi‑bin/printenv.cgi">Environment

Набор символов A href обозначает начало тега ссылки. За этим набором символов следует адрес (или назначение), заключенный в двойные кавычки. Слово Environment отображается на экране; этим определяется область, в результате щелчка на которой выполняется сценарий printenv.cgi. Тег обозначает конец описания ссылки.

Пример файла main.shtml:

$ pg main.shtml

Last modified:


THE MAY DAY OPERATIONS CENTER

Stand‑by to stand‑to


This page has been visited times


To see your environment settings just click

here


Ниже приведен сценарий printenv.cgi, выводящий на печать значения параметров среды. В сценарии используется команда env. Тег

 применяется для сохранения форматирования (вывода табуляции и пробелов).                             

$ pg printenv.cgi

#!/bin/sh

# printenv.cgi

# вывод на печать настроек Web–сервера с помощью команды env

echo "Content‑type: text/html"

echo ""

echo "

"                             

env

echo "

"

Рис. 29.5. Страница, включающая ссылку для просмотра переменных среды
#img_11.png

На рис. 29.5 показано, как выглядит страница с добавленной ссылкой.

После щелчка на ссылке отображаются настройки среды (рис. 29.6). Эти настройки могут слегка отличаться в каждом конкретном случае. При выполнении различных сценариев возможно изменение настроек с целью адаптации к новой среде.

Рис. 29.6. Страница, отображающая значения текущих переменных

 

29.4.6. Другие общие переменные среды

В табл. 29.2 представлены наиболее часто применяемые переменные среды cgi. Значения некоторых из этих переменных могут быть просмотрены с помощью команды env либо set.

Таблица 29.2. Общие переменные cgi Web–сервера

DOCUMENT ROOT Основной каталог Web–сервера, куда загружаются документы
GATEWAY_INTERFACE Редакция cgi
HTTP_ACCEPT Другие подтвержденные типы MIME
HTTP_CONNECTION Предпочитаемое подключение HTTP
HTTP_HOST Имя локального хост–компьютера
HTTP USER AGENT Клиентский броузер
REMOTE_HOST Удаленный хост–компьютер
REMOTE_ADDR [3] IP–адрес удаленного хост–компьютера
REQUEST_METHOD Метод, используемый для передачи информации
SCRIPT FILENAME Абсолютное имя пути сценария cgi
SCRIPT_NAME Относительное имя пути сценария cgi
SERVER_ADMIN Адрес электронной почты Web–администратора
SERVER_NAME Хост–имя, DNS либо IP–адрес сервера
SERVER_PROTOCOL Протокол, используемый для реализации соединения
SERVER_SOFTWARE Наименование программного обеспечения Web–сервера
QUERY_STRING Передаваемые данные из метода GET
CONTENT_TYPE Тип MIME
CONTENT_LENGTH Количество байтов, передаваемых с помощью метода post

Для отображения значения переменных можно заключить эти переменные в небольшой сценарий cgi, а затем вызывать данный сценарий в случае, если нужно проверить значение переменной.

$ pg evncgi.cgi

#!/bin/sh

#envcgi.cgi

#вывод на печать настроек web–сервера с помощью команды env

echo "Content‑type: text/html"

echo ""

echo "

"                             

echo "CGI Test ENVIRONMENTS"

echo "SERVER_SOFTWARE=$SERVER_SOFTWARE"

echo "SERVER_NAME=$SERVER_NAME"

echo "GATEWAY_INTERFACE=$GATEWAY_INTERFACE"

echo "SERVER_PROTOCOL=$SERVER_PROTOCOL"

echo "SERVER_PORT=$SERVER_PORT"

echo "REQUEST_METHOD=$REQUEST_METHOD"

echo "HTTP_ACCEPT=$HTTP_ACCEPT"

echo "PATH_INFO=$PATH_INFO"

echo "PATH_TRANSLATED=$PATH_TRANSLATED"

echo "QUERY_STRING=$QUERY_STRING"

echo "SCRIPT_NAME=$SCRIPT_NAME"

echo "REMOTE_HOST=$REMOTE_HOST"

echo "REMOTE_ADDR=$REMOTE_ADDR"

echo "REMOTE_USER=$REMOTE_USER"

echo "AUTH_TYPE=$AUTH_TYPE"

echo "CONTENT_TYPE=$CONTENT_TYPE"

echo "CONTENT_LENGTH=$CONTENT_LENGTH"

echo "

"

 

29.5. Введение в методы get и post

 

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

После того как пользователь выполнил ввод или выбрал некоторые данные в форме, он может щелкнуть на кнопке send для передачи введенной информации сценарию, в данном случае -cценарию cgi. Как только информация будет введена, "в игру вступают" методы get и post.

 

29.5.1. Метод get

Для любой формы по умолчанию используется метод get. Это один из методов применяемых для выборки файлов из статических HTML–страниц.

Как только пользователь щелкнет на кнопке submit, информация, которая была выбрана или выбирается пользователем, добавляется к URL сервера в виде закодированной строки. Затем эта закодированная строка присваивается переменной среды сервера, query_string. Переменная request_method также используется для хранения метода формы.

Создание простой формы

Создадим простую форму,_ реализующую ссылку из документа main.shtml на сценарий books.cgi.

Вставьте следующие две строки после последней записи ссылки, которая была создана в файле main.shtml:


Basic form using GET method Form1

Теперь введите следующий код и сохраните его в файле books.cgi; не забудьте поместить этот файл в каталог cgi‑bin.

$ pg books.cgi

#!/bin/sh

# сценарий books.cgi

echo "Content‑type: text/html"

echo ""

echo ""

echo ""

# вызов books_result.cgi, затем пользователь щелкает на кнопке отправки

echo "

"

echo "

CGI FORM

"

#текстовое поле, результаты ввода присвоены переменной с именем 'contact' echo "Your Name:

"

#раскрытие выбранного пункта меню, присвоенного переменной 'film'

echo ""

# раскрытие выбранного пункта меню, присвоенного переменной 'actor'

echo ""

echo "

"

# имена переменных флажков 'view_cine' и 'view_vid'

echo "Do you watch films at the..
"

echo " Cinema"

echo " On video"

echo "

"

# результаты ввода, присвоенного переменной 'textarea'

echo "Tell what ls your best film, or just enter some comments
"

echo ""

echo "
"

echo ""

echo "

" echo "" echo ""

Действие form action выбирается, как только пользователь щелкнет на кнопке 'Send it', в результате чего вызывается сценарий books_result.cgi. В этом случае будет использоваться метод get.

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

Текстовое поле, предназначенное для ввода пользовательского имени, имеет длину 30 символов; результаты ввода присваиваются переменной contact.

Первое раскрывающееся меню обеспечивает выбор любимого пользовательского фильма; выбранная опция присваивается переменной film.

Второе раскрывающееся меню обеспечивает выбор любимого актера; выбранная опция присваивается переменной actor.

Можно установить один или оба флажка, выполнив щелчок мышью на требуемом варианте. Выбранные значения хранятся в переменных view_cine и view_vid. Если пользователь указывает один из флажков, переменные должны иметь значение "on".

Область текстового поля обеспечивает ввод большего количества строк текста, чем стандартное текстовое поле (текст, разбитый на 30 столбцов и 4 строки, в нашем случае(, а вся введенная информация присваивается переменной textarea.

Для отсылки данных в качестве типа ввода указывается слово submit. Чтобы очистить форму, щелкните на кнопке clear.

Введите следующий сценарий cgi, назовите его books_result.cgi и сохраните его в каталоге cgi‑bin.

$ pg books_result.cgi

#!/bin/sh

#сценарий books_result.cgi

#вывод на печать настроек web–сервера env для метода get

echo "Content‑type: text/html"

echo ""

echo "

"                             

echo "

"                             

echo " Results from a GET form"

echo "REQUEST_METHOD : $REQUEST_METHOD"

echo "QUERY STRING : $QUERY_STRING"

echо "

"

Сценарий отображает значения пары переменных cgi, query_strinG и request_method. Переменная Query_string будет хранить все данные в виде кодированной строки, которая отправлена формой, созданной с помощью сценария books.cgi. Переменная request_method сохраняет тип используемого метода; в данном случае будет выбран метод get. На рис. 29.7 показано, как выглядит форма, созданная с помощью сценария books.cgi.

Рис. 29.7. Форма cgi, использующая метод get

Теперь выполним ввод и отсылку некоторой информации (рис. 29.8). После щелчка на кнопке 'Send it' отображается страница, показанная на рис. 29.9. Значение переменной QUERY_string отображается только частично по причине большой длины строки. Ниже приведена строка, имеющая полную длину:

contact=David+Tansley&f ilm=The+So_md+Of+Music&actor=Bruce+Willis&view_cine=onS,view_vid=onbtextarea=%21%22%A3%A3%24%25 %24%25%5E*%5E%26*%28%29*%2 8%29%28*%OD%OAHow%27s+that+%21%21

Рис. 29.8. Выбор и ввод информации в форму

Рис. 29.9. Информация, отправленная формой, закодирована

Для пересланной информации необходимо иметь следующие поля, присвоенные

переменной query string, показанной выше:

Переменная Значение переменной
contact David Tan$1ey
film The Sound of Music
actor Bruce Willis
view cine Если установлено значение on, то флажок выбран
view_vid Если установлено значение on, то флажок выбран
textarea !"%$%А*А&*о*о(*
How's that it!

Декодирование закодированной строки

После того как пользователь щелкнет на кнопке "submit", информация присваивается переменной query_string, а строка кодируется следующим образом: • Все пробелы заменяются знаками +.

   •  Все поля значений разделяются символами &.

   • Все значения и соответствующие поля разделяются знаками =.

   • Все символы и некоторые специальные символы представляются кодами %ху, где xy является шестнадцатеричным эквивалентом данного символа. При просмотре переменной QUERY_STRING можно заметить, что многие из этих символов представлены переменной textarea.

Протокол cgi определяет, что любые символы в форме %ху (где xy является шестнадцатеричным числом) могут быть преобразованы в эквивалентные символы ASCII. Эти шестнадцатеричные символы состоят из специальных символов &, %, +, =, (, ) и всех других символов, выходящих за рамки десятичного диапазона ASCII с границей 127. Например, символу ( соответствует эквивалент в виде %29.

Шестнадцатеричные символы создаются в том случае, когда пользователь вводит значения в свободные текстовые поля. Однако эти символы могут также являться частью выбранного текста меню. Для выполнения декодирования закодированной строки нужно выполнить следующее:

   • заменить все символы & символами перевода строки;

   • заменить все символы + пробелами;

   • заменить все символы = пробелами;

   • преобразовать все значения %xy в эквивалентные символы ASCII.

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

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

$ pg conv.cgi

#!/bin/sh

#сценарий conv.cgi

#декодирование строки URL

echo "Content‑type: text/html"

echo ""

echo "

"                             

#отображение метода кодированной строки

echo "Method : $REQUEST_METHOD"

echo "Query String : $QUERY_STRING"

echo "


"

#применение редактора sed для замены символов & символами табуляции

LINE=`echo $QUERY_STRING | sed 's/&/ /g'`

for LOOP in $LINE do

# разбивка на поля NAME и TYPE

NAME=`echo $LOOP | sed 's/=/ /g' | awk '{print $1}'`

#получение TYPE, замена всех символов=пробелами, a %hex_num - \xhex_num

#замена всех символов + пробелами

TYPE=`echo $LOOP | sed 's/=/ /g' | awk '{print $2}' | \ sed -e 's/%\(\)/\\\x/g' | sed 's/+/ /g'`

#используется функция printf, которая отображает значения переменных:

#после завершения преобразований шестнадцатеричных значений

printf "${NAME}=${TYPE}\n"

#в переменную VARS записываются значения отдельных полей, которые затем

#передаются команде eval, благодаря чему отдельные поля можно адресовать;

#при этом, если поля содержат пробелы, требуется удвоенная обратная косая черта

VARS=`printf "${NAME}=\\${TYPE}\n"`

eval `printf $VARS`

done

echo "


"

#используется printf для отображения специальных символов в случае их наличия

printf "Your name is : $contact\n"

printf "Your choice of film is : $film\n"

printf "Your choice of actor is : $actor\n"

printf "You watch films at the cinema : $view_cine\n"

printf "You watch films on video : $view_vid\n"

printf "And here are your comments : $textarea\n"

echo "

"

echo ""

Нетрудно заметить, что в данном случае используется функция printf для вывода данных на экран. Причина этому весьма проста. Функция printf выполняет те же действия, что и обычная команда echo, но дополнительно выполняет шестнадцатеричные преобразования. В связи с этим следует сделать небольшое замечание. При использовании функции printf не происходит вставка символа новой строки; для устранения этого недостатка необходимо после каждой функции printf указать символы "\n", Шестнадцатеричные числа, хранящиеся в переменной QUERY_STRING, имеют формат %hex_num. Этот формат будет просто преобразован в формат \xhex_num с помощью потокового редактора sed, а также функции printf, выполняющей все необходимые преобразования. Зачем создавать себе дополнительные трудности, если для решения задачи существует простой способ?

Сохраните указанный выше сценарий под именем conv.cgi в каталоге cgi‑bin. Теперь осталось выполнить небольшое изменение в сценарии books.cgi, в результате чего форма будет вызывать сценарий conv.cgi вместо сценария books_result.cgi. Для этого следует воспользоваться следующей строкой:

Если теперь повторно передать форму (содержащую одну и ту же информацию), получим результаты, приведенные на рис. 29.10.

Теперь, когда строка имеет более удобочитаемый формат, можно выполнить некоторую обработку информации.

Метод get является стандартным методом, применяемым для работы с формами. В зависимости от имеющегося окружения, при использовании метода get существуют две потенциальные проблемы. Вся закодированная строка добавляется к адресу URL при отсылке информации, поэтому отсылаемая информация может быть просмотрена в окне URL, Хотя многие пользователи не видят в этом особой опасности, все же не стоит посылать информацию частного характера с помощью Web или сети.

Рис. 29.10. Полностью декодированные данные формы
#img_16.png

Если пользовательская форма включает множество полей ввода, длина переменной query_string может чрезмерно возрасти. В этом случае многие пользователи для работы с такими формами используют метод post. Этот метод подробно рассматривается в следующем разделе.

 

29.5.2. Метод post

Метод post, также как и метод get, предназначен для работы с закодированными строками. Разница заключается в способе получения данных: метод post считывает данные из стандартного потока. Для отсылки данных с помощью метода post просто замените ключевое слово get словом post в конструкции form action сценария.

Переменная CONTENT_LENGTH будет хранить общее количество байтов, отосланных с применением метода post. Производится считывание строки из потока стандартного ввода, а затем выполняется то же самое преобразование, что и при использовании метода get. Процесс считывания завершается после того, как считанное количество байтов становится равным количеству байтов, хранящихся в переменной CONTENT_LENGTH.

После выполнения небольшого изменения в конструкции form action получится обобщенный декодер форм. Для осуществления считывания из стандартного потока ввода можно использовать команду cat. Ниже показана конструкция, которую следует добавить в сценарий conv.cgi, в результате чего появится возможность использования методов get и post.

if ["$REQUEST_METHOD"="POST"]; then

QUERY_STRING=`cat -`

fi

Обратите внимание на то, что команда cat содержит дефис, благодаря чему эту команду можно применять для считывания данных из стандартного потока ввода.

При использовании метода post осуществляется обычная проверка значения переменной QUERY_string. Затем все символы, поступающие из стандартного потока ввода, присваиваются переменной QUERY_STRING. В этой ситуации возможно использование метода get, поскольку в любом случае требуется получить информацию из переменной querY_string.

Замените строку form action в cgi–сценарии books.cgi:

строкой

Кроме того, будут выполнены небольшие изменения в сценарии conv.cgi, благодаря чему можно будет проверять значения, введенные в текстовые поля, а также определять установленные флажки. Обновленный сценарий будет иметь следующий вид:

$ pg conv.cgi

#!/bin/sh

#conv.cgi

#декодирование строки URL

echo "Content‑type: text/html"

echo ""

echo "

"                             

# это post ???

if [ "$REQUEST_METHOD"="POST" ]; then

QUERY_STRING=`cat -`

fi

# отображение имени метода и кодированной строки

echo "Method : $REQUEST_METHOD"

echo "Query String : $QUERY_STRING"

echo "


"

# используется sed для замены & символом табуляции

LINE=`echo $QUERY_STRING | sed 's/&/ /g' `

for LOOP in $LINE

do

NAME=`echo $LOOP | sed 's/=/ /g' | awk '{print $1}'`

TYPE=`echo $LOOP | sed 's/=/ /g' | awk '{print $2}' | \

sed -e 's/%\(\)/\\\x/g' | sed 's/+/ /g'`

# используется printf для преобразования шестнадцатеричных символов

printf "${NAME}=${TYPE}\n"

VARS=`printf "${NAME}=\\${TYPE}\n"`

eval `printf $VARS`

done

echo "


"

if [ "$contact" != "" ]; then

printf "Hello $contact, it's great to meet you\n"

else

printf "You did not give me your name… no comment !\n"

fi

if [ "$film" != " — Pick a Film —" ]; then

printf "Hey I agree, $FILM is great film\n"

else

printf "You didn't pick a film\n"

fi

if i "$actor" != " —- Pick Your Favourite Actor --" ]; then

printf "So you like the actor $actor, good call\n"

else

printf "You didn't pick a actor from the menu\n"

fi

if [ "$view_cine"="on" ]; then

printf "Yes, I agree the cinema ls still the best place to watch a film\n" else

printf "So you don't go to the cinema, do you know what you're missing\n" fi

if [ "$view_vid"="on" ]; then

printf "I like watching videos at home as well\n"

else

printf "No video!!. you're missing out on all the classics to rent or buy\n'

fi

if [ "$textarea" != "" ]; then

printf " And here are your comments…OK $textarea\n"

else

printf "No comments entered, so no comment !\n"

fi

echo "

"

echo ""

Обратите внимание, что в этом сценарии везде используется функция printf; хотя в некоторых случаях могут быть задействованы конструкции echo (когда не требуется доступ к переменным). Применение функций printf улучшает восприятие сценариев.

Теперь загрузим форму и осуществим тестирование путем отсылки некоторых данных с помощью метода post:

http://<имя_сервера>/cgi‑bin/books.cgi

На рис. 29.11 иллюстрируются данные, введенные на Web–страницу. После завершения ввода некоторых данных щелкните на кнопке "Send". Результаты выполнения этой операции показаны на рис. 29.12.

Рис. 29.11. Форма cgi, в которой используется метод post
#img_17.png

Сценарий опрашивает различные переменные для того, чтобы установить факт ввода информации. Затем будет выполнена дальнейшая обработка, позволяющая убедиться в том, что все поля имеют значения. Если значения имеются не для всех полей, форма возвращается пользователю и отображается запрос на повторный ввод информации. Как только форма будет корректно заполнена, ее можно добавить в файл. Таким образом можно создавать небольшие базы данных.

#img_18.png

Рис. 29.12. Данные формы были полностью декодированы с помощью метода post

Практическое применение сценария cgi

Создадим сценарий, который будет выполнять некоторую полезную обработку. Пусть это будет отчет какой‑то фиктивной компании, именуемой Wonder Gifts.

Файл отчета содержит номера различных товаров, проданных в каждом квартале 1998 г. Номера товаров соответствуют отделам Stationery, Books и Gifts.

Наша задача -cоздать отчет, который основан на запросе Пользователя. Пользователь может делать выборку по номеру квартала либо по названию отдела. Необходимо выполнить дополнительную обработку, которая заключается в суммировании месячных продаж товаров по кварталам. Результаты могут выводиться на экран, принтер либо на экран и принтер одновременно.

В данном случае форма будет содержать два раскрывающихся меню и переключатель. Одно меню предназначено для выборки по кварталам, второе — для выборки по отделам. Переключатель служит для выбора устройства вывода. В нашем примере отчет выводится только на экран; переключатели выполняют демонстрационную роль.

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

$ pg qtr_1998.txt

STAT 1998 1st 7998 4000 2344 2344
BOOKS 1998 1st 3590 1589 2435 989
GIFTS 1998 1st 2332 1489 2344 846
STAT 1998 2nd 8790 4399 4345 679
BOOKS 1998 2nd 889 430 2452 785
GIFTS 1998 2nd 9822 4822 3555 578
STAT 1998 3rd 8911 4589 2344 8690
BOOKS 1998 3rd 333 1489 6322 889
GIFTS 1998 3rd 2310 1483 3443 778
STAT 1998 4th 9883 5199 2344 6456
BOOKS 1998 4th 7333 3892 5223 887
GIFTS 1998 4th 8323 4193 2342 980

Сценарий формы.

$ pg gifts.cgi

t!/bin/sh

# сценарий gifts.cgi …. используется POST

echo "Content‑type: text/html"

echo ""

echo ""

echo ""

# gifts_result.cgi используется для обработки вывода этой формы

echo ""

echo "

"

echo "


"

echo "

GIFTS Inc
"

echo "QUARTERLY REPORT

"

echo "


"

echo "Department: "

echo "Quarter End:"

echo "

"

echo "Report To Co To:
"

echo "Printer"

echo "Screen"

echo "Both"

echo "


"

echo ""

echo ""

echo ""

echo ""

echo ""

Переменной dept присваивается выбранное значение для отдела; переменной qtr присваивается номер выбранного квартала. Переменной stdout присваивается значение "printer", "screen" или "both"; в качестве значения по умолчанию выбирается screen (это значение указывается с помощью слова "CHECKED"). Ниже приведен сценарий, обрабатывающий полученную информацию.

$ pg gifts_result.cgi

#!/bin/sh

#сценарий gifts_result.cgi

#Декодирование строки URL

еcho "Content‑type: text/html"

echo ""

echo "

"                             

# это post ???

if [ "$REQUEST_METH0D" = "POST" ]; then

QUERY_STRING=`cat -`

fi

# декодирование

# используется sed для замены & символом табуляции

LINE=`echo $QUERY_STRING | sed 's/&/ /g'`

for LOOP in $LINE

do

NAME=`echo $LOOP | sed 's/=/ /g' | awk '{print $1}'`

TYPE='echo $LOOP | sed 's/=/ /g' | awk '{print $2}' | \

sed -e 's/%\(\)/\\\x/g' | sed 's/+/ /g'`

# используется printf при выполнении шестнадцатеричных преобразований VARS=`printf "${NAME}=\\${TYPE}\n"`

eval `printf $VARS`

done

echo "


"

echo "

GIFTS Inc
"

echo "

Quarter End Results

"

echo "


"

#нужно изменить имена полей со STATIONERY на STAT

#для осуществления корректного поиска

if [ "$DEPT"="STATIONERY" ]; then

dept=STAT

fi

# считывание из файла qtr_1995.txt

TOTAL=0

while read DEPT YEAR Q P1 P2 Р3 Р4

do

if [ "$DEPT"="$DEPT" -a "$Q"="$qtr" ]; then

TOTAL=`expr $P1 + $P2 + $P3 + $P4`

fi

continue

done

echo "

"

echo " TOTAL ITEMS SOLD IN THE $DEPT DEPARTMENT"

echo "is $TOTAL IN THE $qtr QUARTER"

echo "


"

# куда будет выведен отчет

if [ "$stdout"="Both" ]; then

echo "This report ls going to the printer and the screen"

else

echo " This report ls going to the $stdout"

fi

echo "

"

echo ""

Первая часть сценария является общей для любой формы, обработка которой осуществляется с помощью метода post. Поскольку отсутствуют шестнадцатеричные значения для преобразования (так как поля ввода являются предопределенными опциями меню), нет нужды в использовании функции printf, но особого смысла в том, чтобы отказаться от использования этой команды, нет. Содержательная часть сценария выполняет считывание из файла qtr_1995.txt.

Цикл while осуществляет считывание и присваивание значений полей переменным dept, year, q, p1, Р2, P3, Р4 соответственно. Затем выполняется проверка значения переменной $dept (значение, отправленное пользователем) и переменной dept; результат конкатенируется с результатом другой проверки с помощью оператора AND. Если значение переменной $qtr (значение, отосланное пользователем) равно значению переменной Q, имеет место соответствие. Все числа, содержащиеся в сравниваемой строке, добавляются вместе.

В настоящее время в нашем распоряжении имеется сценарий формы и сценарий, предназначенный для обработки информации, пересылаемой формой (запустите этот сценарий). Введите URL (либо создайте соответствующую ссылку на главной странице):

http://<имя_сервера>/cgi‑bin/gifts.cgi

Результаты показаны на рис 29.13.

Рис. 29.13. Выборка квартальной информации для дальнейшей обработки
#img_19.png

Сценарий обрабатывает информацию, выбранную пользователем, и генерирует вывод, показанный на рис. 29.14.

Рис. 29.14. Обработка завершена, вывод результатов

 

29.5.3. Заполнение списка

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

Следующий сценарий реализует заполнение раскрывающегося списка данными, содержащимися в текстовом файле list Этот файл находится во временном каталоге, но не в корневом каталоге web–сервера. Цикл while используется для считывания содержимого (построчно( из файла. Для заполнения списка используется следующий кода:

echo "

Выбранный элемент присваивается переменной menu_selection. Ниже приводится сценарий, заполняющий элементы меню; действие формы не указывается.

$ pg populat.cgi

#!/bin/sh

#сценарий populat.cgi

#заполнение раскрывающегося списка значениями из текстового файла

echo "Content‑type: text/html"

echo ""

echo ""

echo ""

echo "

CGI FORM….populat.cgi..populate pull‑down list from a text

file

"

echo ""

echo ""

echo ""

echo ""

 

29.5.4. Автоматическое обновление Web–страницы

При использовании cgi для программирования заданий, выполняющих функции мониторинга либо контроля, часто бывает удобно выполнять обновление страниц в непрерывном режиме. Для этого вызывается пользовательский сценарий или страница. Ниже приводится тег, вызывающий выполнение сценария dfspace.cgi каждые 60 секунд.

"

Здесь ключевым словом является слово Refresh. Благодаря его использованию Web–сервер получает сведения о загрузке данной страницы, а строка "content=60" задает время (в секундах( между повторными загрузками. Для обновления сценария просто добавьте имя сценария в качестве части адреса URL.

В распоряжении автора имеются несколько контролирующих сценариев, выполняющих опрос всех основных хостов в сети. Благодаря их применению можно сразу же определить, какие хосты выполняются, а какие -oтключены. Более симпатичный вид сценарию придает использование в тексте вместо опций on и off зеленых и красных шариков.

Ниже приводится сценарий, использующий часть вывода df и отображающий файловую систему и количество полей в таблице.

Следующий сегмент кода реализует заголовок таблицы, в который помещаются наименования колонок. При использовании таблиц с неотформатированным выводом может происходить потеря данных.

echo "

cols="2">"

echo "

"

echo "

"

Параметр cellspacing устанавливает расстояние между внутренними и внешними границами таблицы. Параметр border хранит число, определяющее толщину табличной рамки. Параметр col s определяет количество столбцов в таблице. Ниже приведена основная часть описываемого сценария.

df | sed 1d | awk '(print $5"\t"$6>' | while read percent mount

do

echo "

"

done

С помощью команды df выполняется перенаправление посредством редактора sed для удаления заголовка, затем выполняется перенаправление к awk и считывание в пятом и шестом столбцах. Результаты присваиваются переменным percent и mount.

Аббревиатура TR обозначает строку таблицы, а TD — табличные данные. Тем самым определяется место, куда направляется информация.

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

$ pg dfspace.cgi

#!/bin/sh

# сценарий dfspace.cgi

echo "Content‑type: text/html"

echo ""

# автоматическое обновление каждые 60 секунд

echo ""

echo ""

echo "


"

echo "LINUX. PC Filesystems"

echo "

- Capacity % - - File System -
$percent$mount

cols="2">"

echo "

"

echo "

"

# получение вывода из df, но сначала фильтруется нужная информация!

df | sed 1d | awk '{print $5"\t"$6}' | while read percent mount

do

echo "

"

done

echo "

- Capacity % - - File System -
$percent$mount
"

echo ""

При вводе URL

http://<имя_сервера>/cgi‑bin/dfspace.cgi

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

Рис. 29.15. Использование вывода команды df для генерирования таблиц

 

29.6. Заключение

Сценарии cgi обеспечивают создание весьма привлекательного пользовательского интерфейса. Страницы HTML могут использоваться в качестве интерфейса для всех распространенных задач, выполняющих обработку информации.

Создаваемые сценарии могут применяться для мониторинга, создания интерфейса, запросов к базам данных и решения других задач. Язык HTML является стандартным форматом для создания документации, поставляемой вместе с программным обеспечением.