Нейл Мэтью - Основы программирования в Linux
□ отделить заголовочную информацию от данных о дорожках и для каждого типа информации использовать отдельный файл.
Только третий вариант позволит нам легко изменять формат файлов, что потребуется, если вы когда-либо захотите превратить вашу базу данных в реляционную (более подробную информацию об этом см. в главе 7), поэтому выберем этот вариант.
Далее нужно решить, какие данные помещать в файлы.
Сначала вы выбираете для заголовка каждого компакт-диска хранение следующей информации:
□ номер компакт-диска в каталоге;
□ название;
□ музыкальный стиль (классика, рок, поп, джаз и т.д.);
□ композитор или исполнитель.
О дорожках вы будете хранить две характеристики:
□ номер дорожки;
□ ее название.
Для объединения двух файлов вы должны сопоставить данные о дорожках с остальной информацией о компакт-диске. Для этого будет использоваться номер компакт-диска в каталоге. Поскольку он уникален для каждого диска, он будет появляться однократно в файле с заголовками и один раз для каждой дорожки в файле с данными о дорожках.
В табл. 2.22 показан пример файла с заголовочными данными, а соответствующий ему файл с данными о дорожках может выглядеть так, как представлено в табл. 2.23.
Таблица 2.22
Catalog Title Type Composer CD123 Cool sax Jazz Bix CD234 Classic violin Classical Bach CD345 Hits99 Pop VariousТаблица 2.23
Catalog Track No. Title CD123 1 Some jazz CD123 2 More jazz CD234 1 Sonata in D minor CD345 1 DizzyДва файла объединены общим полем Catalog (Каталог). Следует помнить о том, что обычно на одну строку файла с заголовочной информацией приходится много строк в файле с данными о дорожках.
Последнее, что мы должны решить, — способ разделения элементов данных. Поля фиксированной ширины, обычные в реляционных базах, — не всегда самый удобный вариант. Другой распространенный способ, применяемый в данном примере, — запятая (т. е. файл со значениями, разделенными запятыми, или CSV-файл).
В упражнении 2.23 только для того, чтобы вы окончательно не запутались, применяются следующие функции:
□ get_return();
□ get_confirm();
□ set_menu_choice();
□ insert_title();
□ insert_track();
□ add_record_tracks();
□ add_records();
□ find_cd();
□ update_cd();
□ count_cds();
□ remove_records();
□ list_tracks().
Упражнение 2.23. Приложение для работы с коллекцией компакт-дисков1. Сначала в примере сценария как всегда стоит строка, обеспечивающая его выполнение как сценария командной оболочки, за которой следует некоторая информация об авторских правах:
#!/bin/bash
# Очень простой пример сценария командной оболочки для управления
# коллекцией компакт-дисков.
# Copyright (С) 1996-2007 Wiley Publishing Inc.
# Это свободно распространяемое программное обеспечение;
# вы можете распространять эту программу и/или изменять ее
# в соответствии с положениями GNU General Public License,
# документа, опубликованного фондом Free Software Foundation;
# либо версии 2 этой лицензии или (по вашему выбору)
# любой более свежей версии.
# Эта программа распространяется в надежде на ее полезность,
# но WITHOUT ANY WARRANTY, (без каких-либо гарантий);
# даже без предполагаемой гарантии MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE (годности
# ее для продажи или применения для определенной цели).
# Более подробную информацию см. в GNU General Public License.
# Вы должны были получить копию GNU General Public License
# вместе с этой программой;
# если нет, пишите в организацию Free Software Foundation,
# Inc. no адресу: 675 Mass Ave, Cambridge, MA 02139, USA.
2. Теперь убедитесь, что установлены некоторые глобальные переменные, которые будут использоваться во всем сценарии. Задайте заголовочный файл, файл с данными о дорожках и временный файл и перехватите нажатие комбинации клавиш <Ctrl>+<C> для того, чтобы удалить временный файл, если пользователь прервет выполнение сценария.
menu_choice=""
current cd=""
title_file="title.cdb"
tracks_file="tracks.cdb"
temp_file=/tmp/cdb.$$
trap 'rm -f $temp_file' EXIT
3. Определите ваши функции так, чтобы сценарий, выполняясь с первой строки, мог найти все определения функций до того, как вы попытаетесь вызвать любую из них в первый раз. Для того чтобы не повторять один и тот же программный код в нескольких местах, сначала вставьте две функции, служащие простыми утилитами:
get_return() (
echo -е "Press return с"
read x
return 0
}
get_confirm() (
echo -e "Are you sure? c"
while true do
read x
case "$x" in
y | yes | Y | Yes | YES )
return 0;;
n | no | N | No | NO )
echo
echo "Cancelled"
return 1;;
*)
echo "Please enter yes or no" ;;
esac
done
}
4. Теперь вы дошли до основной, формирующей меню функции set_menu_choice. Содержимое меню изменяется динамически, добавляя дополнительные пункты при выборе компакт-диска.
set_menu_choice() {
clear
echo "Options :-"
echo
echo " a) Add new CD"
echo " f) Find CD"
echo " c) Count the CDs and tracks in the catalog"
if [ "$cdcatnum" != "" ]; then
echo " 1) List tracks on $cdtitle"
echo " r) Remove $cdtitle"
echo " u) Update track information for $cdtitle"
fi
echo " q) Quit" echo
echo -e "Please enter choice then press return c"
read menu_choice
return
}
ПримечаниеИмейте в виду, что команда echo -е не переносится в некоторые командные оболочки.
5. Далее идут две очень короткие функции, insert_title и insert_track, для пополнения файлов базы данных. Несмотря на то, что некоторые программисты ненавидят однострочные функции вроде этих, они помогают сделать понятнее другие функции.
За ними следует более длинная функция add_record_track, использующая эти функции. В данной функции применяется проверка на соответствие шаблону, чтобы исключить ввод запятых (поскольку мы. используем запятые для разделения полей), и арифметические операции для увеличения номера текущей дорожки на 1, когда вводятся данные о новой дорожке.
insert_title() {
echo $* >> $title_file
return
}
insert_track() {
echo $* >> $tracks_file
return
}
add_record_tracks() {
echo "Enter track information for this CD"
echo "When no more tracks enter q"
cdtrack=1
cdttitle=""
while [ "$cdttitle" != "q" ]
do
echo -e "Track $cdtrack, track title? c"
read tmp
cdttitle=${tmp%%, *}
if [ "$tmp" != "$cdttitle" ]; then
echo "Sorry, no commas allowed"
continue
fi
if [ -n "$cdttitle" ] ; then
if [ "$cdttitle" ! = "q" ]; then
insert_track $cdcatnum, $cdtrack, $cdttitle
fi
else
cdtrack=$((cdtrack-1))
fi
cdtrack=$((cdtrack+1))
done
}
6. Функция add_records позволяет вводить основную информацию о новом компакт-диске.
add_records() {
# Подсказка для начала ввода информации
echo -е "Enter catalog name с"
read tmp
cdcatnum=${tmp%%, *}
echo -e "Enter title c"
read tmp
cdtitle=${tmp%%, *}
echo -e "Enter type c"
read tmp
cdtype=${tmp%%, *}
echo -e "Enter artist/composer c"
read tmp
cdac=${tmp%%, *}
# Проверяет, хочет ли пользователь ввести информацию
echo About to add new entry
echo "$cdcatnum $cdtitle $cdtype $cdac"
# Если получено подтверждение, добавляет данные в конец файла.
# с заголовками
if get_confirm ; then