Текст книги "Linux и UNIX: программирование в shell. Руководство разработчика"
Автор книги: Дэвид Тейнсли
сообщить о нарушении
Текущая страница: 18 (всего у книги 25 страниц)
Ниже приводятся общие строки из потока вывода:
Название
Значение
bel
Звуковой сигнал
blink
Режим мерцания
bold
Двойная интенсивность
civis
Скрыть курсор
clear
Очистка экрана
сnorm
Отобразить курсор
cup
Перемещение курсора на экране в позицию x, у
el
Очистка до конца строки
ell
Очистка к началу строки
smso
Переход в режим отступа
rmso
Выход из режима отступа
smul
Переход в режим подчеркивания
rmul
Выход из режима подчеркивания
sc
Сохранение текущего положения курсора
rc
Восстановление последней позиции курсора
sgr0
Обычный экран
rev
Обратное видео
21.1.2. Числовой вывод
Наиболее распространенный числовой вывод:
Название
Значение
cols
Количество столбцов
it
Настройка табуляции
lines
Количество строк на экране
21.1.3. Поток вывода булевых данных
Команда tput включает незначительное количество булевых операторов.
Название
Значение
chts
Курсор трудно заметить
hs
Имеет строку статуса
21.2. Работа с командой tput
Рассмотрим наиболее распространенные разновидности команды tput, а также методы ее использования в сценариях.
21.2.1. Присвоение имен командам tput
Можно использовать поток вывода всех имен команды tput, присваивая их переменным с более осмысленными наименованиями. При этом применяется следующий формат:
имя переменной='tput name'
21.2.2. Применение булевого потока вывода
Чтобы применить булев поток вывода для команды tput, воспользуйтесь конструкцией if:
STATUS_LINE=`tput hs` if $STATUS_LINE; then
echo "your terminal has a status line"
else
echo "your terminal has NO status line"
fi
21.2.3. Использование команды tput в сценариях
В приведенном сценарии командам tput bel и cl присваиваются более значимые имена.
$ pg tput1
#!/bin/sh
BELL=`tput bel`
CLEAR=`tput cl`
echo $BELL
echo $CLEAR
В следующем сценарии изменяются несколько видеоатрибутов и происходит отображение и сокрытие курсора:
$ pg tput2
#!/bin/sh
BOLD=`tput bold`
REV=`tput rev` NORMAL=`tput sgr0` CURSOR_OFF=`'tput civis` CURSOR_ON=`tput cnorm` tput init
# сокрытие курсора, выделение текста, перестановка текста, отображение курсора
echo $CURSOR_OFF
echo "${BQLD} WELCOME TO THE PIZZA PLACE ${NORMAL}"
echo -e "n${REV} WE ARE OPEN 7 DAYS A WEEK ${NORMAL}"
echo $CURSOR_ON
21.2.4. Генерирование escape–последовательностей
Обратите внимание, что при использовании эмулятора довольно затруднительно скрыть курсор. Это обусловлено несколькими причинами:
1. Некоторые эмуляторы не воспринимают управляющий символ, скрывающий курсор. Желательно, чтобы разработчики программного обеспечения для эмуляторов учли это замечание. В исходный код потребуется внести изменения, реализующие сокрытие курсора.
2. Существует мнение, что некоторые более ранние версии команды tput civis не функционируют должным образом.
Управляющим символом, используемым для сокрытия курсора, является ?251
(буква l). Для возврата в исходное положение применяется символ ?25h.
Все управляющие символы выполняются с помощью escape–последовательности. Обычно за кодом клавиши [Esc] следует символ [. Затем управляющая последовательность подключает или отключает определенный атрибут терминала.
Для генерирования escape–последовательностей можно воспользоваться двумя различными методами. В таблице ниже приводятся оба метода, которые зависят от имеющейся системы. Третий метод можно применить независимо от того, используется система UNIX или Linux, поскольку управляющая последовательность реализована в составе конструкции echo. Именно третий метод и применяется в книге.
Чтобы переслать escape–последовательность и отключить курсор, используется следующий код:
Linux/BSD
echo -e " 33[?251"
System V
echo " 33[?251"
Обобщенный метод
echo "
Клавише [Esc] соответствует код 33. Символ указывает команде echo, что далее следует восьмеричное значение. Например, для вывода на экран символа @ можно применить команду:
echo "@"
Или же для вывода на экран этого символа можно воспользоваться восьмеричным значением символа, которое равно 100.
echo -e "100"
Для System V примените команду:
echo "100"
Результат будет аналогичным.
Команда clear очищает экран и устанавливает курсор в верхнем левом углу экрана. Это положение курсора обычно называется home. При работе с терминалами, относящимися к семейству VT, эту процедуру выполняет последовательность esc [2J. Данную последовательность можно отправить с помощью конструкции echo.
System V echo " 33[2J"
LINUX/BSD echo -e " 33[2J"
При этом следует придерживаться тех же правил, которыми руководствуются при работе с управляющими символами, помещенными в текстовые файлы. Не следует применять методику "вырезать и вставить", поскольку в этом случае будет утеряно специальное значение символов. Чтобы вставить управляющие символы, отображающие курсор, воспользуйтесь следующим кодом:
echo '
Здесь даны указания о том, что следует воспользоваться комбинацией клавиш [Ctrl+V], затем нажать клавишу [Esc] и после этого ввести символы [?25h.
Если при использовании команды tput civis курсор не исчезает и при этом не запущен эмулятор, воспользуйтесь следующим небольшим сценарием. С его помощью можно скрыть либо отобразить курсор. Вы можете подробно изучить приведенную
функцию либо перевернуть пару страниц и сразу ознакомиться с результатами выполнения сценария.
$ pg cursor
#!/bin/sh
#отображение|сокрытие курсора
#отображает или скрывает курсор при работе с терминалами vt100, 200, 220, meth220
#замечание: функционирует при нормальном ttу–соединении при использовании
#некоторых win–эмуляций
#проверьте TERM env для вашего типа!
_ОРТ=$1
if [ $# -ne 1 ]; then
echo "Usage: `basename $0` cursor [on | off]"
exit 1
fi
case "$_OPT" in
on|ON|On)
# отображение курсора
ON=`echo ^[[?25h`
echo $ON
;;
off|OFF|Off)
# сокрытие курсора
OFF=`'echo ^[ [?251`
echo $OFF
;;
*)echo "Usage: cursor on | off" exit 1
;;
esac
21.2.5. Изменение положения курсора
Команду tput также можно применять для отображения курсора в произвольном месте экрана. При этом используется следующий формат:
cup r c
где r – это номер ряда (строки) в нижней части экрана, а с – номер столбца на экране.
Лучше применять эту команду в форме функции, тогда можно указывать значения для строки и столбца.
xу()
(
#_R= row, _C=column
_R=$1
_C=$2
tput cup $_R $_C
}
clear
xy 1 5
echo -n "Enter your name :"
read NAME
xy 2 5
echo -n "Enter your age :"
read AGE
Конечно, желательно передавать строку для отображения; ниже приводится небольшая модификация этого сценария.
ху()
{
#_R= row, _C=column
_R-$1
_TEXT=$3
tput cup $_R $_C
echo -n $_TEXT
}
Сценарий можно вызвать следующим образом:
xy 5 10 "Enter your password :" read CODE
21.2.6. Центрирование отображаемого текста
При центрировании текста на экране нужно быть предельно внимательным. С помощью команды tput необходимо получить столбцы, затем получить значение для длины строки, исключить это значение из столбцов tput и разделить ответ на две части. В дальнейшем нужно только указать номер строки, где отобразится данная строка.
Ниже приводится часть кода, который выполняет эту задачу. Чтобы просмотреть строки файла и центрировать на экране весь текст, достаточно выполнить небольшое изменение.
Введите символы, нажмите клавишу [Return], и текст отобразится в середине экрана начиная со строки 10.
echo -n "input string :"
read STR
# быстрый способ вычисления длины строки
LEN=`echo $STR | wc -с`
COLS=`tput cols`
NEW_COL=`expr ($COLS – $LEN ) / 2`
xy 10 $NEW_COL
echo $STR
Чтобы указанная функция отличалась большей гибкостью, при ее вызове можно
использовать текст и номер строки. Функция будет иметь следующий вид:
centertxt() {
_ROW=$1 _STR=$2
# быстрый способ получения длины строки
LEN=`echo $_STR | wc -c`
COLS=`tput cols`
_NEW_COL=`expr {$COLS – $LEN ) / 2`
xy $_ROW $_NEW_COL
echo $_STR
}
Чтобы вызвать функцию, следует применить команду:
centertxt 15 "THE MAIN EVENT"
или аналогичную команду, но с использованием строки в качестве аргумента:
centertxt 15 $1
21.2.7. Определение атрибутов терминала
Рассмотрим сценарий, в котором с помощью команды tput производится обращение к базе данных terminfo. С помощью некоторых команд tput отображаются управляющие коды терминала.
$ pg termput
#!/bin/sh
#termput
#инициируйте tput для терминала
tput init
clear
echo "tput <> terminfo"
infocmp -l $TERM | while read LINE
do
case $LINE in
bel*) echo "$LINE: sound the bell" ;;
blink*) echo "$LINE: begin blinking mode";;
bold*) echo "$LINE: make it bold" ;;
el*) echo "$LINE: clear to end of line" ;;
civis*) echo "$LINE: turn cursor off";;
cnorm*) echo "$LINE: turn cursor on ";;
clear*) echo "$LINE: clear the screen" ;;
kcuul*) echo "$LINE: up arrow ";;
kcubl*) echo "$LINE: left arrow ";;
kcufl*) echo "$LINE: right arrow ";;
kcudl*) echo "$LINE: down arrow ";;
esac done
Команда infocmp извлекает из файла базы данных terminfo информацию о терминале. Если нужно просмотреть файл, содержащий сведения о настройках терминала, выполните команду:
$ infocmp $TERM
Ниже с помощью сценария termput отображается поток вывода для некоторого терминала:
$ termput
tput <> terminfo
bel=^G,: sound the bell
blink=E[5m, : begin blinking mode
bold=E[1m,: make it bold
civis=E[?251,: turn cursor off
clear=E[HE[J,: clear the screen cnorm
‑E[?25h,; turn cursor on
el=E[K,: clear to end of line
ell=E[lK,: clear to end of line
kcubl=E[D,: left arrow
kcudl=E[B,: down arrow
kcufl=E[C,: right arrow
kcuul=E[A,: up arrow
21.2.8. Применение функциональных клавиш при работе со сценариями
С помощью команды cat можно обращаться к специальным клавишам ([F1], [стрелка_вверх] и т. д.). Введите команду cat -v, затем нажмите любую управляющую клавишу и просмотрите, что отобразится в нижней строке. Когда просмотр завершится, нажмите комбинацию клавиш [Ctrl+C].
В следующем примере вызывается команда cat и используются клавиши [F1] (^[OP), [F2](^[OQ) и [стрелка_вверх](^[[A).
$ cat -v
^[ОР
^[OQ
^[[А
Эта информация позволяет применять рассмотренные символы в сценариях в качестве дополнительных методов, обеспечивающих интерактивный режим работу пользователя.
В приведенном ниже сценарии распознаются клавиши [F1], [F2], а также клавиши стрелок. Пользовательские значения могут быть иными, поэтому выполните команду cat, чтобы уточнить, какие значения соответствуют управляющим клавишам терминала.
$ pg control_keys
#!/bin/sh
#управляющие_клавиши
#для вставки примените последовательность '
uparrowkey='^[[А'
downarrowkey='^[[В'
leftarrowkey='^[[D'
rightarrowkey='^[[С'
f1key='^[OP'
f2key='^[OQ'
echo -n " Press a control key then hit return"
read KEY
case $KEY in
$uparrowkey) echo "UP arrow";;
$downarrowkey) echo "DOWN arrow";;
$leftarrowkey) echo "LEFT arrow";;
$rightarrowkey) echo "RIGHT arrow";;
$f1key) echo "F1 key";;
$f2key) echo "F2 key";;
*) echo "unknown key $key";;
esac
21.2.9. Применение различных цветов
Благодаря применению цвета можно придать экрану, где. отображается поток ввода, более привлекательный вид. При работе с цветами используется стандарт ANSI. Однако не все цвета можно применить во всех системах. Предлагаем перечень наиболее часто употребляемых цветов.
Цвета переднего плана
Значение
Цвет
30
черный
31
красный
32
зеленый
33
желтый (или коричневый)
34
голубой
35
пурпурный
36
синий (циан)
37
белый (или серый)
Фоновые цвета
Значение
Цвет
40
черный
41
красный
42
зеленый
43
желтый (или коричневый)
44
голубой
45
пурпурный
46
синий (циан)
47
белый (или серый)
Для отображения цветов переднего плана и фоновых цветов применяется следующий формат:
21.2.10. Генерирование цветов
Для генерирования цвета управляющие символы встраиваются в конструкцию echo. Данный метод применяется при работе с цветным терминалом и произвольной системой. Как и в случае с управляющими символами, цвета можно генерировать с помощью escape–последовательностей, встраиваемых в конструкцию echo. Для создания черного фона с передним планом зеленого цвета воспользуйтесь командой:
Linux/BSD: echo -e " 33[40;32m"
System V: echo " 33[40;32m"
Обобщенный метод: echo "
При использовании обобщенного метода, т. е. комбинации клавиш [Ctrl+V], нажмите клавишу [Esc], затем введите символы [40;32m. Обобщенный метод и применяется далее в книге.
Возможно, лучше поместить конструкции echo, отвечающие за воспроизведение цвета, в конструкцию case, а затем оформить все это в виде функции. Ниже, приводится функция цвета case.
colour ()
(
# формат цвет_фона; цвет_переднего_планаm
case $1 in
black_green)
echo '^[[40;32m';;
black_yellow)
echo '^[[40;33m';;
black_white)
echo '^[[40;37m';;
black_cyan)
echo '^[[40;36m';;
red_yellow)
echo '^[[41;33m';;
black_blue)
echo '^[[40;34m';;
esac
}
Чтобы задать красный цвет фона и желтый цвет переднего плана, примените команду:
colour red_yellow
Для использования цветов в сценариях выполните следующие действия:
colour whatever echo something
# измените на другой цвет
colour whatever
echo something
Обычно по умолчанию в качестве цветов экрана используются черный и белый. Рассмотрим, как изменить эту установку, чтобы фоновым цветом был черный, а цветом переднего плана – зеленый. С этой целью в файл .profile достаточно добавить конструкцию echo, которая создает требуемую комбинацию.
Ниже приводится пример кода для управления экраном.
$ pg colour_scr
#!/bin/sh
# colour_scr
tput init
MYDATE=`date +%D`
colour ()
{
# формат цвет_фона; цвет_лереднего_планаm
case $1 in
black_green)
echo '^[[40;32m' ;;
black_yellow)
echo '^[[40;33m' ;;
black_white)
echo '^[[40;37m' ;;
black_cyan)
echo '^[[40;36m' ;;
black_red)
echo '^[[40;31m' ;;
esac
}
xy() #xy
• для вызова: ху строка, столбец,"text"
• переход к координатам ху на экране {
#_R=row, _C=column
_R=$1
_C=$2
_TEXT=S3
tput cup $_R $_C
echo -n $_TEXT
}
center()
{
center
#центрирование строки текста на экране
#для вызова: center "строка" номер_строки
_STR=$1
_ROW=$2
# неудачный способ получения длины строки
LEN=`echo $_STR | wc -с`
COLS=`tput cols`
HOLD_COL=`expr $COLS – $LEN`
NEW_COL=`expr $HOLD_COL / 2`
tput cup $_ROW $NEW_COL
echo -n $_STR
}
tput clear
colour red_yellow
xy 2 3 "USER: $LOGNAME"
colour black_cyan
center "ADD A NEW WARP DRIVE TO A STAR SHIP" 3
echo -e "ff"
center " " 4
colour black_yeliow
xy 5 1 " "
xy 7 1 "_____"
xy 21 1 " "
center "Star Date $MYDATE " 22
xy 23 1 "____ _____________"
colour black_green
xy 6 6 "Initials :"
read INIT
xy 8 14
echo -n "Security Code No: :"
read CODE
xy 10 13
echo -n "Ship's Serial No: :"
read SERIAL
xy 12 14
echo -n "Is it on the Port Side :"
read PORT
colour red_yellow
center " Save This Record [Y..N]:" 18
read ans
# восстановление обычных цветов экрана
colour black_white
Нетрудно заметить, что этот сценарий не включает методов проверки. В данном случае все нормально. Сценарий просто демонстрирует, как можно раскрасить экран.
21.2.11. Улучшение внешнего вида меню
Помните ли вы меню, которое создавалось при обсуждении циклов while? Внесем в сценарий этого меню некоторые усовершенствования. В результате оно будет включать следующие варианты выбора:
1: ADD A RECORD
2: VIEW A RECORD
3: PAGE ALL RECORDS
4: CHANGE A RECORD
5: DELETE A RECORD
P: PRINT ALL RECORDS
H: Help screen
Q: Exit Menu
В сценарии обработки этого меню применяется функция read_char, поэтому пользователь не должен при выборе опций меню нажимать клавишу (Return]. Для игнорирования сигналов 2, 3 и 15 применяется команда trap (более подробно это команда обсуждается далее), поэтому пользователь может не прерывать работу с меню.
Меню также имеет возможности по управлению доступом. Пользователи, обладающие определенными привилегиями, могут вносить изменения в записи или удалять их. Остальным пользователям разрешается только добавлять записи, просматривать их и выводить на экран. Список действительных пользователей с указанием уровней доступа находится в файле priv.user.
Если к меню попытаются обратиться пользователи, имена которых не содержатся в указанном файле, отобразится сообщение о том, что эти пользователи не имеют права выполнять данное приложение. После этого выполнение приложения завершается.
Опции меню скрывают системные команды. Если нужно ознакомиться с подтверждением данных при обновлении файла, обратитесь к главе 22.
Ниже приводится файл priv.user, содержащий имена пользователей, которые могут или не могут удалять записи и вносить в них изменения. Из приведенного текста видно, что пользователи root, dave и matty не имеют права вносить изменения в файлы баз данных, а пользователи peter и louise располагают этим правом.
$ pg priv.user
#файл доступа priv.user для меню apps
#его изменение является рискованным !!!!
#формат реализуют записи USER AMEND/DELETE
#например, запись "root yes" означает, что пользователь root может
#обновлять или удалять записи
#запись "dave no" означает, что пользователь dave не может обновлять или удалять записи
root no
dave no
peter yes
louise yes
matty no
Чтобы проверить права доступа пользователей, сначала просмотрим файл. При этом игнорируются строки комментария, а все другие строки перенаправляются в файл temp.
user_level()
(
while read LINE
do
case $LINE in
#*);;
*) echo $LINE >>$HOLD1 ;;
esac done < $USER_LEVELS
FOUND=false
while read MENU_USER PRIV
do
if [ "$MENU_USER"="$USER" ]; then
FOUND=true
case $PRIV in
yes|YES) return 0 ;;
no|NO) return 1 ;;
esac
else
continue
fi
done <$HOLD1
if [ "$FOUND"="false" ]; then
echo "Sorry $USER you have not been authorised to use this menu"
exit 1
fi
На следующем этапе просматривается заново отформатированный файл. Переменной FOUND присваивается значение "ложь". Теперь файл temp включает только описание имен и прав доступа; именам пользователей и правам доступа назначаются переменные. Чтобы уточнить, соответствует ли имя в файле значению user, производится проверка; значение user берется из команды whoami, расположенной в начале сценария. Если совпадение не найдено, выполняется проверка с помощью конструкции else, и с помощью команды continue обработка продолжается на следующей итерации.
Этот процесс длится до тех пор, пока все имена пользователей не будут просмотрены. При этом имя пользователя сравнивается со значением переменной USER. Если при просмотре всего файла совпадение не установлено, конструкция test в конце программного кода проверяет значение переменной FOUND. Если значением переменной является "ложь", пользователю отказывается в дальнейшей работе.
Если в процессе выполнения цикла while устанавливается искомое соответствие, переменной found присваивается значение "истина". Затем с помощью конструкции case выбираются права доступа. При этом возвращается 1 для обычных прав доступа либо 0 – для расширенных прав доступа.
Когда пользователь приступает к внесению изменений в запись или к удалению записи, выполняется проверка. Этот процесс основывается на коде возврата функции, описанном выше. В приведенном сценарии либо выполняется сортировка файла passwd, либо отображается каталог:
if user_level; then
sort /etc/passwd
else
restrict
fi
Функция restrict просто выводит на экран сообщение о нарушении прав доступа.
Вышеприведенная проверка может быть реализована за один цикл. Однако кодирование выглядит более привлекательно, если применяется метод работы с двумя файлами. В результате значительно облегчается отладка кода.
Чтобы выйти из меню, пользователь выбирает пункт q или Q, в результате чего вызывается функция для очистки экрана. Когда пользователь завершает работу с любым обширным сценарием, очень удобно в этом случае воспользоваться функцией. Это позволяет увеличить количество команд, выполняемых пользователем при завершении работы. Кроме того, значительно улучшается читабельность кода.
Ниже приводится соответствующий сценарий.
$ pg menu2
#!/bin/sh
#menu2
#СЦЕНАРИЙ ГЛАВНОГО МЕНЮ
#игнорирование CTRL‑C и прерывания QUIT
trap "" 2 3 15
MYDATE=`date +%d/%m/%Y`
THIS_HOST=`hostname -s`
USER=`whoami`
#файл, описывающий права доступа пользователя USER_LEVELS=priv.user
#файл для хранения
HOLDl=holdl.$$
#функция задания цвета
colour ()
{
# формат цвет_фона; цвет_переднего_планаm
case $1 in
black_green)
echo '^[[40;32m' ;;
black yellow)
echo '^[[40;33m' ;;
black_white)
echo '^[[40;37m' ;;
Ьlаск_суап)
echo '^[[40;36m' ;;
red_yellow)
echo '^[[41;33m' ;;
esac
}
# чтение значения клавиши
get_char()
(
#get_char
#сохранение текущих установок stty SAVEDSTTY=`stty -g`
stty cbreak
dd if=/dev/tty bs=1 count=1 2> /dev/null
stty -cbreak
# восстановление установок stty
stty $SAVEDSTTY
}
# отображение или сокрытие курсора
cursor ()
{
#cursor
#отображение/сокрытие курсора
_OPT=$1
case $_OPT in
on) echo '^[[?25h';;
off) echo '^[[?251';;
*) return 1;;
esac }
# проверка прав доступа пользователя
restrict ()
{
colour red_yellow
echo -e -n "nn 07Sorry you are not authorised to use this function"
colour black_green
}
user_level () {
# user level
# просмотр файла priv.user
while read LINE
do
case $LINE in
# игнорирование комментариев
#*);;
*) echo $LINE >> $HOLD1 ;;
esac
done < $USER_LEVELS
FOUND=false
while read MENU_USER PRIV
do
if [ "$MENU_USER"="$USER" ]; then
FOUND=true
case $PRIV in
yes|YES)
return 0 ;;
no|NO)
return 1 ;;
esac
else
# соответствие не найдено, чтение следующей записи
continue
fi
done <$HOLD1
if [ "$FOUND"="false" ]; then
echo "Sorry $USER you have not been authorised to use this menu"
exit 1
fi
}
# вызывается, если пользователь выполняет выход из программы
my_exit()
{
#my_exit
#вызывается, если пользователь выбирает выход из сценария!
colour black_white
cursor on
rm *.$$
exit 0
}
tput init
# отображение на экране уровня доступа пользователя
if user_level; then
ACCESS="Access Mode ls High"
else
ACCES3="Access Mode ls Normal"
fi
tput init
while :
do
tput clear
colour black_green
cat < MAYDAY
$ACCESS
MAYDAY
colour black_cyan
echo -e -n "tYour Choice [1,2,3,4,5,P, H,Q] >"
@ read CHOICE
CHOICE=`get_char`
case $CHOICE in
1) ls ;;
2) vi ;;
3) who ;;
if userlevel; then
ls -l |wc
else
restrict
fi ;;
5)
if userlevel; then
sort /etc/passwd
else
restrict
fi ;;
esac
echo -e -n "tHit the return key to continue"
read DUMMY
done
Подобное меню можно вызвать с помощью команды exec (из файла profile). Пользователи не могут изменить эту последовательность действий. Такой подход распространен в случае с пользователями, работающими только с приложениями UNIX или Linux и не использующими возможности интерпретатора shell.
21.3. Заключение
Команда tput позволяет значительно улучшить контроль со стороны пользователей за выполнением сценариев. Применение цветов улучшает внешний вид меню. Будьте осторожны при использовании гаммы цветов; цвета могут быть привлекательны для вас, но не отвечать вкусам пользователя, вынужденного применять сценарий. Работа со сценариями значительно облегчается при использовании управляющих символов. Это особенно проявляется в случае, когда пользователи осуществляют ввод информации путем выбора назначенных клавиш.
ГЛАВА 22
Создание экранного ввода
Когда речь идет об экранном вводе, или вводе данных, подразумевают ввод информации (в нашем случае с помощью клавиатуры), а затем – проверку достоверности введенных данных. Если данные удовлетворяют неким критериям, они сохраняются.
Существуют функции для проверки некоторых условий, например длины строки. Можно также проверить, состоит ли строка из чисел или символов. Эти функции применяются наравне с другими функциями, рассматриваемыми в данной книге.
В главе обсуждаются следующие темы:
• проверка достоверности вводимых данных;
• добавление, удаление, обновление записей и их просмотр;
• сценарии, выполняющие обновление файлов.
Материал главы может с первого взгляда показаться сложным. В этом случае советуем вначале просмотреть главу, а затем вернуться к ней позже. Реализация проверки вводимых данных требует довольно большого программного кода. Однако для выявления всех возможных ошибок код должен выполнять проверку на наличие наиболее вероятных ошибок.
Рассмотрим отдельные задачи, из которых складывается общая система по обновлению файлов, включающая такие функции, как добавление, удаление, обновление и просмотр записей. В результате создается система хранения актуальной информации О сотрудниках. Записи в файле DBFILE содержат следующие сведения:
Поле
Длина
Разрешен ввод следующей информации
Описание
Staff number
10
Числовая
Номер служащего по штатному расписанию
First name
20
Символьная
Имя служащего
Second name
20
Символьная
Фамилия служащего
Department
Accounts
Отдел, где работает служащий
IT
Services
Sales
Claims
Поля разделяются двоеточием (:). Например:
Каждое задание представляет собой завершенный сценарий. Небольшие части кода дублируются в некоторых представленных ниже сценариях. И это не случайно, поскольку настоящая глава посвящена описанию системы обновления данных. Когда я впервые приступил к написанию сценариев, то обнаружил явный дефицит документации, написанной простым и понятным языком. Особенно недостает описаний совместного использования базы данных и системы по обновлению файлов.
Для связи различных заданий реальный сценарий должен иметь соответствующее меню или модуль. Чаще всего для этой цели используется оболочка функций, содержащихся в файле, совместно с каким‑либо меню сценария. Каждый сценарий включает команду trap; благодаря ее использованию игнорируются сигналы 2, 3 и 15.
22.1. Добавление записей
При добавлении записи в файл выполняются следующие задачи:
1. Подтверждение вводимых данных.
2. Внесение записи в файл.
Сначала необходимо связать вместе некоторые функции. Тогда можно узнать, являются ли поля числовыми или символьными, а также уточнить их размеры. В этом и состоит подтверждение вводимых данных. Подтверждение данных осуществляется при добавлении записей, а также при их обновлении. К счастью, некоторые из' требуемых функций уже имеются в вашем арсенале.
Функция для проверки длины строки:
length_check()
{
# length_check
# $1=строка, $2= длина строки не превышает этого значения
_STR=$1
_МАХ=$2
_LENGTH=`echo $_STR | awk '{print length ($0) }"`
if [ "$_LENGTH" -gt "$_MAX" ]; then
return 1 else
return 0 fi }
Функция, выполняющая проверку наличия в строке исключительно числовых данных:
a_number ()
• a_number
• $1=string {
_NUM=$1
_NUM=`echo $1 awk '{if($0~/[^0-9]/) print "1")'`
if [ "$_NUM" != "" ]
then
return 1
else
return 0
fi
}
Функция, позволяющая определить, состоит ли строжа исключительно из одних символов:
characters()
#characters
#$1=string
{
_LETTERS_ONLY=$1
_LETTERS_ONLY=`echo $1|awk '{if($0~/[^a‑zA‑Z]/) print "l"}'`
if [ "$_LETTERS_ONLY" != "" ]
then
return 1 else
return 0 fi
}
При просмотре полей можно просто вызвать необходимую функцию и затем проверить коды возврата.
Чтобы сообщения находились на экране до тех пор, пока пользователь не нажмет на клавишу для их удаления, нужно воспользоваться командным приглашением. Следующая функция реализует командное приглашение read_a_char.
continue_promptYN() {
# continue_prompt
echo -n "Hit any key to continue.."
DUMMY=`read_a_char`
}
Когда вводятся данные пользователя, содержащие номер служащего, нужно убедиться, что ранее подобная информация не вводилась. Поле должно быть уникальным. Существует несколько способов для выполнения этой задачи; в данном случае применяется команда grep. С помощью команды grep выполняется поиск номера служащего, который содержится в строке _CODE. Если утилита awk не возвращает какого‑либо значения, то дублирующиеся значения отсутствуют и функция завершает выполнение с кодом возврата 0. Ниже приводится код этой функции. (Обратите внимание, что для нахождения точного соответствия в команде grep используется выражение "$_CODE>". Двойные кавычки служат для сохранения значения переменной; при использовании одинарных кавычек ничего возвращаться не будет.)
check_duplicate() {
#check_duplicate
#проверка дубликата номера служащего
_CODE=$1
MATCH="grep "$_CODE>" $DBFILE"
echo $_CODE
if [ "$MATCH"="" ]; then
return 0 # нет дублирования
else
return 1 # дубликат найден
fi
}
Ниже приводится часть программного кода, выполняющая проверку номера
служащего. Функционирование этого программного кода объясняется дальше.
while : do
echo -n "Employee Staff Number :"
read NUM
# проверка вводимых данных
if [ "$NUM" != "" ]; then
if a_number $NUM; then
# номер OK
NUM_PASS=0
else
NUM_PASS=1
fi
if length_check $NUM 10; then
# длина OK
LEN_PASS=0
else
LEN_PASS=1
fi
# проверка наличия дубликатов…
if check_duplicate $NUM; then
# нет дубликатов
DUPLICATED=0
else
DUPLICATED=1
echo "Staff Number: There ls already an employee with this number"
continue_prompt
fi
# проверка значений всех трех переменных; все они должны выполняться
if [ "$LEN_PASS"="0" -a "$NUM_PASS"="0" -a "$DUPLICATE"="0" ]
then
break
else
echo "Staff Number: Non‑Numeric or Too Many Numbers In Field" continue_prompt
fi
else
echo "Staff Number: No Input Detected, This Field Requires a Number" continue_prompt
fi
done
Вся информация обрабатывается в цикле while (фактически, каждое поле, содержащее записи данных, обрабатывается в отдельном цикле while). Поэтому, если имеется недействительная запись, последует запрос о просмотре ее исходного значения.
После просмотра номера служащего проверяется, содержатся ли в поле некоторые данные:
if [ "$NUM" != "" ]
Если поле не содержит данные для ввода, не выполняется часть then конструкции if. В части else, которая завершает код подтверждения поля, отображается следующее сообщение:
Staff Number: No Input Detected, This Field Requires a Number
Часть then производит все необходимые проверки правильности вводимых данных. При условии, что имеются вводные данные, вызывается функция a_number. Эта функция проверяет, содержит ли передаваемая строка числовые данные; если это так, функция возвращает значение 0, в противном случае возвращается значение 1, На базе возвращаемых значений флагу num_pass присваивается либо значение о (успешный возврат – наличие строки из чисел), либо значение 1 (неудачный возврат -cтрока не является числовой).
Затем вызывается функция length check. Эта функция передает не только строку, но и максимальное число символов, содержащихся в строке. В данном случае передается десять символов. Если количество символов меньше или равно максимальной величине, отображается значение 0; иначе возвращается значение 1. Флаг len_PASS принимает либо значение 0 (в случае успешного возврата, когда длина строки не превышает максимального значения), либо значение 1 (при неудачном возврате, если получена строка, длина которой равна максимальному значению).