355 500 произведений, 25 200 авторов.

Электронная библиотека книг » Дэвид Тейнсли » Linux и UNIX: программирование в shell. Руководство разработчика » Текст книги (страница 19)
Linux и UNIX: программирование в shell. Руководство разработчика
  • Текст добавлен: 15 октября 2016, 00:39

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


Автор книги: Дэвид Тейнсли



сообщить о нарушении

Текущая страница: 19 (всего у книги 25 страниц)

Проверим, имеются ли дубликаты для номеров служащих. Эту задачу выполняет функция check_duplicate. Если дубликаты не обнаружены, флагу DUPLICATE присваивается значение 1. Теперь нужно убедиться, что все три флага имеют значение 0 (ошибки отсутствуют). Для этого воспользуемся логической функцией and. При выполнении части then обе части уравнения должны принять истинное значение.

Если проверка завершилась успешно, значение поля подтверждается. Поскольку цикл while выполняется непрерывно, следует с помощью команды break прервать его выполнение.

if [ "$LEN_PASS" = "0" -a "$NUM_PASS" = "0" -a "$DUPLICATE" = "0"]; then

break

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

Staff Number: Non‑Numeric or Too Many Numbers In Field

Действительно, значение одного поля подтверждается.

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

while : do

echo -n "Employee's First Name :"

read F_NAME

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

if characters $F_NAME; then

F_NAME_PASS=0

else

F_NAME_PASS=1

fi

if length_check $F_NAME 20; then

LEN_PASS=0 else

LEN_PASS=1

fi

if [ "$LEN_PASS"="0" -a "$F_NAME_PASS"="0" ]; then

break

else

echo "Staff First Name: Non‑Character or Too Many Characters In Field"

continue_prompt

fi

else

echo "Staff First Name: No Input Detected, This Field Requires Characters" continue_prompt

fi

done

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

while :

do

echo -n "Company Department :"

read DEPART

case $DEPART in

ACCOUNTS|Accounts|accounts) break;;

SALES|Sales|sales) break;;

IT|It|it) break;;

CLAIMS|Claims|claims) break;;

SERVICES|Services|services) break;;

*) echo "Department: Accounts, Sales, IT, Claims, Services";;

esac

done

Когда все поля подтверждены, отображается приглашение с вопросом, следует ли сохранять эту запись. С этой целью применяется функция continue_promptYN, к которой мы уже обращались ранее, используя Y или N в качестве ответа. Если пользователь нажимает клавишу [Return], можно также передать ответ, заданный по умолчанию.

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

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

echo "$NUM:$F_NAME:$S_NAME:$DEPART" >> $DBFILE

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

Разделителем поля служит двоеточие. Затем файл сортируется по полю, содержащему фамилию, а поток вывода направляется в файл temp. После этого файл перемещается назад, в исходный файл DEFILE. Во время перемещений файла выполняется проверка кода завершения. При появлении каких‑либо затруднений пользователь получает соответствующее сообщение.

Вот как выглядит поток данных вывода в случае добавления записи:

ADD A RECORD

Employee Staff Number : 23233

Employee's First Name : Peter

Employee's Surname : Wills

Company Department : Accounts

Do You wish To Save This Record [Y..N] [Y]:

saved

А теперь обратите внимание, какой вид имеет файл DBFILE после добавления нескольких записей:

$ pg DBFILE

32123:Liam:Croad:Claims 2399:Piers:Cross:Accounts 239192:John:Long:Accounts 98211:Simon:Penny:Services 99202:Julie:Sittle:XT 23736:Peter:Wills:Accounts 89232:Louise:Wilson:Accounts 9l811:Andy:Wools:IT

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

$ pg dbase_add

#!/bin/sh

#dbase_add

#добавление записи

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

trap "" 2 3 15

#файл temp содержит файлы

DBFILE=DBFILE

HOLD1=HOLD1.$$

read_a_char ()

#read_a_char

#сохранение установок

SAVEDSTTY=`stty -g`

stty cbreak

dd if=/dev/tty bs=1 count=1 2> /dev/null

stty -cbreak

stty $SAVEDSTTY

}

continue_promptYN()

#вызов: continue_prompt "string to display" default_answer

{

# continue_prompt

_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 ls $_DEFAULT" ;;

esac

echo $_ANS

done

)

continue_prompt() {

# continue_prompt

echo -n "Hit any key to continue.."

DUMMY=`read_a_char`

}

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

#вызов: a_number $1=number _NUM=$1

_NUM=`echo $1|awk '{if($0~/[^0-9]/) print "1"}'`

if [ "$_NUM" != "" ]

then

# ошибки

return 1

else

return 0

fi

}

characters()

#characters

#вызов: char_name string {

_LETTERS_ONLY=$1

_LETTERS_ONLY=`echo $1 | awk '{if ($0~/[^a‑zA‑Z]/) print "1")'`

if [ "$_LETTERS_ONLY" != "" ]

then

# ошибки

return 1

else

# содержит только символы

return 0

fi

}

check_duplicate() {

#check_duplicate

#проверка дублирования номера служащего

#для вызова: check_duplicate строка _CODE=$1

MATCH=`grep "$_CODE>" $DBFILE`

echo $_CODE

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

return 0 # нет дубликата

else

return 1 # дубликат обнаружен

fi

}

add_rec()

{

# add_rec

# == STAFF NUMBER

while :

do

echo -n "Employee Staff Number :"

read NUM

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

if a_number $NUM; then

NUM_PASS=0

else

NUM_PASS=1

fi

if length_check $NUM 10; then

LEN_PASS=0

else

LEN_PASS=1

fi

# проверка наличия дубликатов… if check_duplicate $NUM; then

DUPLICATED=0

else

DUPLICATE=1

echo "Staff Number: There ls already a 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 :

do

echo -n "Employee's First Name:"

read F_NAME

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

if characters $F_NAME; then

F_NAME_PASS=0

else

F_NAME_PASS=1

fi

if length_check $F_NAME 20; then

LEN_PASS=0

else

LEN_PASS=1

fi

# oбa условия должны быть истинными для выхода из этого цикла if [ "$LEN_PASS"="0" -a "$F_NAME_PASS"="0" ]; then

break

else

echo "Staff First Name: Non‑Character or Too Many Characters In Field" continue_prompt

fi

else

echo "Staff First Name: No Input Detected, This Field Requires Characters"

continue_prompt

fi

done

# == Фамилия

while :

do

echo -n "Employee's Surname :"

read S_NAME

if [ "$S_NAME" != "" ]; then if characters $S_NAME; then

$_NAME_PASS=0

else

$_NAME_PASS=1

fi

if length_check $S_NAME 20; then

LEN_PASS=0

else

LEN_PASS=1

fi

if [ "$LEN_PASS"="0" -a "$S_NAME_PASS"= "0" ]; then

break else

echo "Staff Surname: Non‑Character or Too Many Characters In Field" continue_prompt fi else

echo "Staff Surname: No Input Detected, This Field Requires Characters" continue_prompt fi done

# == Отдел

while :

do

echo -n "Company Department :" read DEPART case $DEPART in

ACCOUNTS|Accounts|accounts) break;;

SALES|Sales|sales) break;; IT|It|it) break;;

CLAIMS|Claims|claims) break;;

Services|SERVICES|services) break;;

*) echo "Department: Accounts, Sales, IT, Claims, Services";; esac done )

# основная программа

clear

echo -e "tttADD A EMPLOYEE RECORD"

if [ -s $DBFILE ]; then :

else

echo "Information: Creating new file to add employee records"

>$DBFILE fi

add_rec if continue_promptYN "Do You wish To Save This Record " "Y"; then

echo "$NUM:$F_NAME:$S_NAME:$DEPART" >> $DBFILE

echo "record saved"

sleep 1

sort +2 -t: $DBFILE > $HOLD1 2> /dev/nuil

if [ $? -ne 0 ]; then

echo "problems trying to sort the file..check it out"

exit 1 fi

mv $HOLD1 $DBFILE if [ $? -ne 0 ]; then

echo "problems moving the temp sort file..check it out"

exit 1 fi

else

echo " record not saved"

sleep 1 fi

22.2. Удаление записей

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

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

   1. Поиск записи.

   2. Отображение записи.

   3. Подтверждение процедуры удаления.

   4. Обновление файла.

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

обработке. Можно применить команду grep или утилиту awk. Но поскольку данный файл, скорее всего, содержит не более 100 записей, просмотрим его и определим наличие совпадений.

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

Чтобы применить команду grep или утилиту awk, можно выполнить поиск в файле DBFILE:

echo "enter the surname to search "

read STR

#при работе с awk используйте команду

awk -F: '/$STR/' DBFILE

#при работе с grep используйте команду

grep "$STR" DBFILE

#либо команду

grep "$STR >" DBFILE

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

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

Чтобы сохранить значения переменной ifs, примените следующую команду:

SAVEDIFS=$IFS

Заменить значение переменной ifs двоеточием можно, выполнив команду

IFS=:

По завершении работы с переменной IFS вы можете легко восстановить ее значение:

IFS=$SAVEDIFS

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

get_rec () {

# get_rec

clear

echo -n "Enter the employee surname :"

read STR

if [ "$STR"="q" ]; then

return 1 fi

REC=0

MATCH=no

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

while read CODE F_NAME S_NAME DEPART

do

REC=`expr $REC + 1` tput cup 3 4

echo -n " searching record.. $REC"

if [ "$S_NAME"="$STR" ]; then

MATCH=yes

display_rec

break

else

continue

fi

done

else

echo "Enter a surname to search for or q to quit"

fi

if [ "$MATCH"="no" ]; then

no_recs

fi

}

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

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

Но не такой:

[ -z $STR ]

При выборе первой проверки пользователю достаточно нажать на клавишу [Return], чтобы выполнить команду trap. Во втором случае устанавливается лишь наличие строки нулевой длины.

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

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

if continue_promptYN "Do You Wish To DELETE This Record" "N"; then

echo "DEL"

grep -v $STR DBFILE >$HOLD1 2> /dev/null

if [ $? -ne 0 }; then

echo "Problems creating temp file $HOLD1.. check it out"

exit 1 fi

Удаление записи выполняется выполнением команды grep с опцией -v. В этом случае с помощью строки STR отображаются все несовпадающие поля. (Эта строка содержит фамилию, которая запрашивается пользователем при удалении записи.)

Поток данных вывода для команды grep перенаправляется во временный файл, где выполняется сортировка. Затем временный файл заменяет исходный файл DBFILE.

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

Enter the employee surname :Wilson

searching record,. 6

EMPLOYEE NO: 69232 FIRST NAME : Louise SURNAME : Wilson DEPARTMENT : Accounts

Do You Wish To DELETE This Record [Y..N] [N] :

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

$ pg dbase_del

#!/bin/sh

#dbase_del

#удаление записи

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

trap "" 2 3 15

#Файл данных

DBFILE=DBFILE

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

HOLD1=HOLD1.$$

HOLD2=HOLD2.$$

continue_promptYN(} {

#continue_prompt

_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|Yes|YES)

return 0;;

n|N|No|NO)

return 1;;

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

esac

done

}

display_rec()

{

#display_rec

#можно воспользоваться командой cat << документ

tput cup 5 3

echo "EMPLOYEE NO: $CODE" echo "FIRST NAME : $F_NAME" echo "SURNAME :$S_NAME"

echo "DEPARTMENT : $DEPART"

echo -e "nn"

}

no_recs () {

# no_recs

echo -e "nnSorry could not find a record with the name $STR"

}

get_rec () {

# get_rec

clear

echo -n "Enter the employee surname :"

read STR

if [ "$STR"="q" ]; then

return 1

fi

REC=0

MATCH=no

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

while read CODE F_NAME S_NAME DEPART

do

REC=`expr $REC + 1`

echo -n " searching record.. $REC"

if [ "$S_NAME" = "$STR" ]; then

MATCH=yes

display_rec

break

else

continue

fi

done << $DBFILE

else

echo "Enter a surname to search for or q to quit"

fi

if [ "$MATCH"="no" ]; then

no_recs

fi

}

SAVEDIFS=$IFS

IFS=:

get_rec

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

if continue_promptYN "Do You Wish To DELETE This Record" "N"; then echo "DEL"

grep -v $STR DBFILE >$HOLD1 2> /dev/null if [ $? -ne 0 ]; then

echo "Problems creating temp file $HOLD1..check it out" exit 1 fi

mv $HOLD1 DBFILE if [ $? -ne 0 ]; then

echo "Problems moving temp file..check it out" exit 1 fi

# сортировка файла после изменений

sort +2 -t: $DBFILE >$HOLD2 2> /dev/null if [ $? -ne 0 ]; then

echo "problems trying to sort the file..check it out"

exit 1 fi

mv $HOLD2. $DBFILE if [ $? -ne 0 ]; then

echo "problems moving the temp sort file..check it out"

exit 1 fi else

echo "no deletion"

# удаление отсутствует

fi # если нужно удалить

fi # если совпадает

# восстановление установок IFS IFS=$SAVEDIFS

22.3. Обновление записей

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

Когда обнаруживается корректная запись, все переменные поля записи с помощью переменной, выполняющей присваивание по умолчанию, назначаются переменной temp:

: [переменная, заданная по умолчанию:=переменная)

Пользователь может просто нажать клавишу [Return] для тех полей, значения которых изменять нежелательно. Затем переменная temp заменяется значением, заданным по умолчанию. Для выполнения произвольных обновлений можно просто вводить в соседние поля новые значения.

echo -n -e "EMPLOYEE NO: $C0DEn"

echo -n "FIRST NAME : [$F_NAME] >"

read _F_NAME

: ${_FNAME:=$P_NAME}

Для реального обновления файла достаточно снова воспользоваться командой grep с опцией -v. Все записи обновляются по отдельности и перенаправляются во временный файл. Номер служащего задается в виде строки команды grep:

grep ~v $C0DE $DBFILE >$HOLD1

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

echo "$CODE:$_F_NAME:$_S_NAME:$_DEPART" >> $HOLD1 mv $HOLD1 $DBFILE

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

Enter the employee surname :Penny

searching record.. 7

EMPLOYEE NO: 98211

FIRST NAME : Simon

SURNAME : Penny

DEPARTMENT : Services

ls this the record you wish to amend [Y..N] [Y]:

amending

EMPLOYEE NO: 98211

FIRST NAME : [Simon] >

SURNAME : [Penny] >

DEPARTMENT : [Services] >Accounts Ready to save this record [Y..N] [Y] :

Полный сценарий, выполняющий обновление записей:

$ pg dbasechange

#!/bin/sh

# dbasechange

   • обновление записи

   • игнорирование сигналов trap "" 2 3 15

   • временные файлы DBFILE=DBFILE HOLD1=HOLD1.$$ HOLD2=HOLD2.$$

continue_promptYN()

{

   • continue_jprompt _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

done }

display_rec() {

   • отображение_записи

   • можно применить команду cat « документ, но нежелательно tput cup 5 3

echo "EMPLOYEE NO: $CODE" echo "FIRST NAME : $F_NAME" echo "SURNAME : $S_NAME" echo "DEPARTMENT : $DEPART" echo -e "nn" }

no_recs()

{

# no_recs

echo -e "nnSorry could not find a record with the name $STR" }

get_rec ()

{

# get_rec

clear

echo -n "Enter the employee surname :"

read STR

if [ "$STR"="q" ]; then

return 1 fi

REC=0

MATCH=no

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

while read CODE F_NAME S_NAME DEPART do

REC=`expr $REC + 1` tput cup 3 4

echo -n " searching record.. $REC" if [ "$S_NAME"="$STR" ); then

MATCH=yes

display_rec

break

else

continue

fi

done

else

echo "Enter a surname to search for or q to quit"

fi

if [ "$MATCH"="no" ]; then

no_recs

fi

# основная программа

SAVEDIFS=$IFS

IFS=: get_rec

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

if continue_promptYN "Is this the record you wish to amend" "Y"

then

echo "amending"

# нельзя изменить код служащего .

echo -n -e "EMPLOYEE NO: $CODEn"

echo -n "FIRST NAME : [$F_NAME] >"

read _F_NAME

: ${_FNAME:=$F_NAME}

echo -n "SURNAME : [$S_NAME] >"

read _S_NAME

: ${_S_NAME:=$S_NAME}

echo -n "DEPARTMENT : [$DEPART] >"

read _DEPART

: ${_DEPART:=$DEPART}

grep -v $CODE $DBFILE >$HOLD1

if [ $? -ne 0 ]; then

echo "Problems creating temporary file..check it out"

exit 1

fi

if continue_promptYN "Ready to save this record" "Y"; then

echo "$CODE:$_F_NAME:$_S_NAME:$_DEPART" >> $HOLD1

mv $HOLD1 $DBFILE

if [ $? -ne 0 ]; then

echo "Problems moving temporary file…check it out"

fi

echo " Record Amended" # сортировка файла после изменений sort +2 -t: $DBFILE >$HOLD2 2> /dev/null

if [ $? -ne 0 ]; then

echo "problems trying to sort the file..check it out"

exit 1

fi

mv $HOLD2 $DBFILE if [ $? -ne 0 ]; then

echo "problems moving the temp sort file..check it out"

exit 1

fi

else

#если обновление прерывается

echo "Amend aborted"

exit 0

fi

else

# если не выполняется обновление

echo "no amending"

# нет удаления

fi

# если желательно удалить

fi

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

IFS=$SAVEDIFS

22.4. Просмотр записей

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

if [ "$STR"="all" ]; then

echo "Surname Name Employee Code"

echo "______________________________"

cat $DBFILE | awk -F: '{print $2"t"$3"tt"$1}' | more

return 0

fi

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

pg << MAYDAY

RECORD No : $REC

EMPLOYEE NUMBER : $CODE

EMPLOYEE NAME : $F_NAME

EMPLOYEE SURNAME : $S_NAME

EMPLOYEE DEPARTMENT : $DEPART

MAYDAY

Вот как выглядит поток вывода при просмотре записи:

Enter the employee surname to view or all for all records:Wilson searching record… 8


EMPLOYEE NO

89232

FIRST NAME

Peter

SURNAME

Wilson

DEPARTMENT

IT

Do You Wish To Print This Record [Y..N] [N] :

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

$ pg dbaseview

#!/bin/sh

#dbaseview

#просмотр записей

#игнорирование сигналов trap "" 2 3 15

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

HOLD1=HOLD1.$$

DBFILE=DBFILE

continue_promptYN ()

{

#continue_prompt

_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|Yes|YES)

return 0;;

n|N|No|NO)

return 1;;

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

esac

done

}

display_rec() {

#diaplay_rec

#можно применить команду cat <<.

tput cup 5 3

echo "EMPLOYEE NO: $CODE"

echo "FIRST NAME : $F_NAME"

echo "SURNAME : $S_NAME"

echo "DEPARTMENT : $DEPART"

echo -e "nn"

}

no_recs () {

# no_recs

echo -e "nnSorry could not find a record with the name $STR"

}

get_rec () {

# get_rec

clear

echo -n "Enter the employee surname to view or all for all records:"

read STR

if [ "$STR"="q" ] ; then

return 1 fi

if [ "$STR"="all" ]; then # просмотр всех записей

echo "Surname Name Employee Code" echo"____________________________________"

cat $DBFILE |awk -F: '{print $2"t"$3"tt"$1}' | more

return 0

fi

REC=0

MATCH=no

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

while read CODE F_NAME S_NAME DEPART

do

REC=`expr $REC + 1`

tput cup 3 4

echo -n " searching record.. $REC" if [ "$S_NAME"="$STR" ]; then

# обнаружено имя

MATCH=yes

display_rec

break

else

continue

fi

done <$DBFILE

else

echo "Enter a surname to search for or q to quit"

fi

if [ "$MATCH"="no" ]; then

no_recs

fi

}

# главная программа

SAVEDIFS=$IFS

IFS=:

get_rec

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

if continue_promptYN "Do You Wish To Print This Record" "N"; then

lpr << MAYDAY

RECORD No: $REC

EMPLOYEE NUMBER : $CODE

EMPLOYEE NAME : $F_NAME

EMPLOYEE SURNAME : $S_NAME

EMPLOYEE DEPARTMENT : $DEPART

MAYDAY

else

echo "No print of $S_NAME"

# не отображается fi # если желательно отображение

fi # если имеется совпадение

IFS=$SAVEDIFS

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

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

В среде программистов известно довольно старое изречение. Звучит оно примерно так: "Мусор на входе, мусор на выходе… кого это заботит, только б не было слишком поздно". Это означает, что если не проверять входные данные сценариев, в поток вывода может попасть ненужная информация.

ГЛАВА 23

Отладка сценариев

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

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

В этой главе рассматриваются следующие темы: – распространенные ошибки; – применение команды set.

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

Чаще всего при написании сценариев пропускаются кавычки либо ключевое слово fi в конце конструкции if.

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

23.1. Наиболее распространенные ошибки

23.1.1. Ошибки, связанные с циклом

Если сообщение об ошибке появляется при выполнении конструкций for, while, until или case, то это может означать, что фактический блок инструкций некорректно определен. Возможно, было пропущено зарезервированное слово, требуемое в данной ситуации.

Ниже в сообщении об ошибке содержится слово "done", которое помогает разобраться в сути проблемы. Теперь пользователь знает, что нужно внести изменения в конструкцию while. При внимательном просмотре кода следует проверить наличие всех необходимых зарезервированных слов для конструкции while, например "do", или ключевого слова для применяемой условной конструкции.

syntax error near unexpected token 'done' line 31: 'done'

23.1.2. Как обычно пропускают кавычки

Второй распространенной ошибкой является элементарный пропуск кавычек. Обратите внимание на приведенный пример. Обычно приходится сталкиваться с большим количеством подобных примеров. Можно посоветовать еще раз изучить сценарий и проконтролировать наличие всех необходимых открывающих и закрывающих кавычек – unexpected EOF while looking for '""' line 36: syntax error

Если требуется настроить отображение сообщения об ошибке, содержащего номер ошибочной строки, то в этом случае обычно применяется опция set nu текстового редактора vi. Это удобно, если просмотр файлов осуществляется с помощью редактора vi. Для настройки отображаемых сообщений откройте окно редактора vi, затем нажмите клавишу [Esc] и введите двоеточие. После этого выполните команду set nu и нажмите клавишу [Return]. В результате этого происходит нумерация строк и можно перейти к той строке, где, по сообщению интерпретатора shell, содержится ошибка.

23.1.3. Проверка на наличие ошибки

Другой распространенной ошибкой является неправильное применение конструкции -eq. Обычно забывают указать число с какой‑либо стороны уравнения.

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

[: missing '] '

23.1.4. Регистр символов

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

23.1.5. Циклы for

При работе с циклом for пользователи иногда забывают в части списка указать знак доллара. В результате список воспринимается как строка.

23.1.6. Команда echo

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

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

23.2. Команда set

При отладке сценария можно использовать команду set. Ниже приведены наиболее часто применяемые отладочные опции команды set.

set -n Считывание, но не выполнение команд set -v Отображение всех строк при считывании set -х Отображение всех команд и их аргументов

Чтобы отключить опцию set, просто замените знак – на знак +. Конечно, привычнее было бы, наоборот, знак + применять для подключения, а знак – использовать для отключения. Но здесь все зависит от привычки.

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

Рассмотрим, как функционирует команда set. Ниже приводится небольшой сценарий, который включает в список переменных определенные имена. Пользователь вводит имя, затем с помощью цикла for просматривается список в поисках соответствия. Обратите внимание, что опция set -x применяется в верхней части сценария, а в нижней части сценария ее действие завершается.

$ pg error

#!/bin/sh

#error

#установка set -x set -x

LIST="Peter Susan John Barry Lucy Norman Bill Leslie"


    Ваша оценка произведения:

Популярные книги за неделю