Нейл Мэтью - Основы программирования в Linux
# Если получено подтверждение, добавляет данные в конец файла.
# с заголовками
if get_confirm ; then
insert_title $cdcatnum, $cdtitle, $cdtype, $cdac
add_record_tracks
else
remove_records
fi
return
}
7. Функция find_cd с помощью команды grep ищет текст с названием компакт-диска в файле с заголовочной информацией. Вам нужно знать, сколько раз была найдена строка, а команда grep только вернет значение, указывающее на то, что строка не была найдена или была найдена многократно. Для решения этой проблемы сохраните вывод в файл, отводящий по одной строке на каждое найденное совпадение, а затем сосчитайте количество строк в файле.
У команды счетчика слов, wc, в выводе есть пробельный символ, разделяющий количества строк, слов и символов в файле. Используйте синтаксическую запись $(wc -l $temp_file) для извлечения первого параметра в выводе и переноса его в переменную linesfound. Если бы вам был нужен другой следующий далее параметр, нужно было бы воспользоваться командой set для установки значений переменных-параметров оболочки из вывода команды.
Изменив значение переменной IFS (Internal Field Separator, внутренний разделитель полей) на запятую, вы сможете разделить поля, разграниченные запятыми. Альтернативный вариант — применить команду cut.
find_сd() {
if [ "$1" = "n" ]; then
asklist=n
else
asklist=y
fi
cdcatnum=""
echo -e "Enter a string to search for in the CD titles c"
read searchstr
if [ "$searchstr" = "" ]; then
return 0
fi
grep "$searchstr" $title_file > $temp_file
set $(wc -l $temp_file)
linesfound=$1
case "$linesfound" in
0)
echo "Sorry, nothing found"
get_return
return 0 ;;
1) ;;
2)
echo "Sorry, not unique."
echo "Found the following"
cat $temp_file
get_return
return 0
esac
IFS=", "
read cdcatnum cdtitle cdtype cdac < $temp_file
IFS=" "
if [ -z "$cdcatnum" ]; then
echo "Sorry, could not extract catalog field from $temp_file"
get_return
return 0
fi
echo
echo Catalog number: $cdcatnum echo Title: $cdtitle
echo Type: $cdtype
echo Artist/Composer: $cdac
echo
get_return
if [ "$asklist" = "y" ]; then
echo -e "View tracks for this CD? c"
read x
if [ "$x" = "y" ]; then
echo
list_tracks
echo
fi
fi
return 1
}
8. Функция update_cd позволит вам повторно ввести сведения о компакт-диске. Учтите, что вы ищите (с помощью команды grep) строки, начинающиеся (^) с подстроки $cdcatnum, за которой следует ", " и должны заключить подстановку значения $cdcatnum в {}. Таким образом, вы сможете найти запятую без специального пробельного символа между ней и номером в каталоге. Эта функция также использует {} для образования блока из нескольких операторов, которые должны выполняться, если функция get_confirm вернет значение true.
update_cd() {
if [ -z "$cdcatnum" ]; then
echo "You must select a CD first"
find_cd n
fi
if [ -n "$cdcatnum" ]; then
echo "Current tracks are :-"
list_tracks
echo
echo "This will re-enter the tracks for $cdtitle"
get_confirm && {
grep -v "^${cdcatnum}, " $tracks_file > $temp_file
mv $temp_file $tracks_file
echo
add_record_tracks
}
fi
return
}
9. Функция count_cds дает возможность быстро пересчитать содержимое базы данных.
count_cds() {
set $(wc -l $title_file)
num_titles=$1
set $(wc -l $tracks_file)
num_tracks=$1
echo found $num_titles CDs, with a total of $num_tracks tracks
get_return
return
}
10. Функция remove_records удаляет элементы из файлов базы данных с помощью команды grep -v, удаляющей все совпадающие строки. Учтите, что нужно применять временный файл.
Если вы попытаетесь применить команду:
grep -v "^$cdcatnum" > $title_file
файл $title_file станет пустым благодаря перенаправлению вывода > до того, как команда grep выполнится, поэтому она будет читать уже пустой файл.
remove_records() {
if [ -z "$cdcatnum" ]; then
echo You must select a CD first find_cd n
fi
if [ -n "$cdcatnum" ]; then
echo "You are about to delete $cdtitle"
get_confirm && {
grep -v "^${cdcatnum}, " $title_file > $temp_file
mv $temp_file $title_file
grep -v "^${cdcatnum}, " $tracks_file > $temp_file
mv $temp_file $tracks_file
cdcatnum=""
echo Entry removed
}
get_return
fi
return
}
11. Функция list_tracks снова использует команду grep для извлечения нужных вам строк, команду cut для доступа к отдельным полям и затем команду more для постраничного вывода. Если вы посмотрите, сколько строк на языке С займет повторная реализация этих 20 необычных строк кода, то поймете, каким мощным средством может быть командная оболочка.
list_tracks() {
if [ "$cdcatnum" = "" ]; then
echo no CD selected yet
return
else
grep "^${cdcatnum}, " $tracks_file > $temp_file
num_tracks=${wc -l $temp_file}
if [ "$num_tracks" = "0" ]; then
echo no tracks found for $cdtitle
else
{
echo
echo "$cdtitle :-"
echo
cut -f 2- -d , $temp_file
echo
} | ${PAGER:-more}
fi
fi
get_return
return
}
12. Теперь, когда все функции определены, можно вводить основную процедуру. Первые несколько строк просто приводят файлы в известное состояние; затем вы вызываете функцию формирования меню set_menu_choice и действуете в соответствии с ее выводом.
Если выбран вариант quit (завершение), вы удаляете временный файл, выводите сообщение и завершаете сценарий с успешным кодом завершения.
rm -f $temp_file
if [ ! -f $title_file ]; then
touch $title_file
fi
if [ ! -f $tracks_file ]; then
touch $tracks_file
fi
# Теперь непосредственно приложение
clear
echo
echo
echo "Mini CD manager" sleep 1
quit=n
while [ "$quit" != "y" ]; do
set_menu_choice
case "$menu_choice" in
a) add_records;;
r) remove records;;
f) find_cd y;;
u) update_cd;;
c) count_cds;;
l) list_tracks;;
b)
echo
more $title_file
echo
get return;;
q | Q ) quit=y;;
*) echo "Sorry, choice not recognized";;
esac
done
# Убираем и покидаем
rm -f $temp_file echo "Finished"
exit 0
Замечания, касающиеся приложенияКоманда trap в начале сценария предназначена для перехвата нажатия пользователем комбинации клавиш <Ctrt>+<C>. Им может быть сигнал EXIT или INT, в зависимости от настроек терминала.
Существуют другие способы реализации выбора пункта меню, особенно конструкция select в оболочках bash и ksh (которая, тем не менее, не определена в стандарте X/Open). Она представляет собой специализированный селектор пунктов меню. Проверьте ее на практике, если ваш сценарий может позволить себе быть немного менее переносимым. Для передачи пользователям многострочной информации можно также воспользоваться встроенными документами.
Возможно, вы заметили, что нет проверки первичного ключа, когда создается новая запись; новый код просто игнорирует последующие названия с тем же кодом, но включает их дорожки в перечень первого названия:
1 First CD Track 1
2 First CD Track 2
1 Another CD
2 With the same CD key
Мы оставляем это и другие усовершенствования в расчете на ваше воображение и творческие способности, которые проявятся при корректировке вами программного кода в соответствии с требованиями GPL.
Резюме
В этой главе вы увидели, что командная оболочка — это мощный язык программирования со своими функциональными возможностями. Ее способность легко вызывать программы и затем обрабатывать их результат делают оболочку идеальным средством для решения задач, включающих обработку текста и файлов.