Упражнение 5.28
Сравните предложенный здесь подход и реализацию команды news с аналогичной командой вашей системы.
5.9 Команды
get
и put
: контроль изменении файла В последнем разделе этой длинной главы мы приведем большой и более сложный пример, в котором продемонстрируем вам взаимодействие языков
shell
,
awk
и
sed
.
Программа развивается по мере того, как мы устраняем ошибки и добавляем в нее новые средства. Иногда полезно сохранять ее разные версии, особенно в ситуации, когда кто-то переносит программу на другую машину, и возникает вопрос: "Что изменилось с тех пор, как мы получили версию вашей программы?" или "Как вы устранили такие- то ошибки?" К тому же наличие копий упрощает эксперимент: если у вас что-либо не получилось, то можно безболезненно вернуться к исходной программе.
Одно из решений состоит в том, чтобы хранить копии всех версий программы, но это трудно организовать и, кроме того, требует большого объема памяти на диске. Мы же будем основываться на подобии последовательных версий, что позволяет хранить только их общую часть. Команда
$ diff -е old new
порождает список команд редактора
ed
, преобразующих файл
old
в
new
. Таким образом, можно хранить все версии на базе одного файла, сохраняя одну полную версию и множество команд редактирования, преобразующих ее в любую другую версию.
Существуют два очевидных решения: хранить целиком последнюю версию и иметь команды редактирования для возврата к старым версиям или хранить самую старую версию и иметь команды редактирования для перехода к новым. Хотя второе решение чуть проще запрограммировать, первое предпочтительнее, поскольку из множества версий почти всегда интереснее выбрать новые.
Мы рассмотрим первое решение. В едином файле, называемом файлом истории, хранится текущая версия, за которой следует множество команд редактирования, преобразующих каждую версию в предыдущую (т.е. более старую). Любой набор команд редактирования начинается такой строкой:
@@@ пользователь дата сводка
Сводка — это одна строка, которая вводится пользователем и описывает изменения.
Для работы с версиями используются две команды:
get
выделяет версию из файла истории, a
put
заносит новую версию в файл истории после запроса на ввод сводки изменений. Прежде чем привести программу, покажем, как выполняются
get
и
put
и как сохраняется файл истории:
$ echo строка текста > junk
$ put junk
Summary: создадим новый файл
Введите описание
get: no file junk.H
Файл-история не существует
put: creating junk.H
…и put создает его
$ cat junk.H
строка текста
@@@ you Sat Oct 1 13:31:03 EDT 1983
сделаем новый файл
$ echo еще строка >>junk
$ put junk
Summary: одна строка добавлена
$ cat junk.H
строка текста
еще одна строка текста
@@@ you Sat Oct 1 13:31:28 EDT 1983 одна строка добавлена
2d
@@@ you Sat Oct 1 13:31:03 EDT 1983 сделаем новый файл
$
Команды редактирования представляют собой одну строку 2, которая исключает вторую строку файла, преобразуя новую версию в исходную:
$ rm junk
$ get junk
Самая новая версия
$ cat junk строка текста еще строка текста
$ get -l junk
$ cat junk
Версия новейшая, но одна
строка текста
$ get junk
Опять самая новая версия
$ replace еще 'другая' junk
Изменим ее
$ put junk
Summary: изменена вторая строка
$ cat junk.H
строка текста
другая строка
@@@ you Sat Oct 1 13:34:07 EDT 1983 одна строка добавлена
2d
@@@ you Sat Oct 1 13:31:03 EDT 1983 создадим новый файл
$
Для получения нужной версии файла в файле истории записаны команды редактирования. Первая группа команд преобразует самую последнюю версию в предыдущую, вторая группа преобразует предыдущую в пред-предыдущую версию и т.д. Таким образом, мы преобразуем новый файл в его старую версию, запуская каждый раз редактор
ed
.
Очевидно, может возникнуть проблема, если в изменяемом файле есть строки, начинающиеся с трех символов. Кроме того, в разделе ошибок описания команды
diff(1)
(см. справочное руководство по UNIX) есть предупреждение о строках, состоящих из одной точки. Мы выбрали
@@@
для разделения команд редактирования, поскольку такая строка является редкостью для обычного текста.
Конечно, было бы полезно показать здесь процесс развития команд
put
и
get
, но из-за ограниченного объема книги мы приведем только их окончательные варианты. Команда
put
проще команды
get
:
# put: install file into history
PATH=/bin:/usr/bin
case $# in
1) HIST=$1.H ;;
*) echo 'Usage: put file' 1>&2; exit 1 ;;
esac
if test ! -r $1
then
echo "put: can't open $1" 1>&2
exit 1
fi
trap 'rm -f /tmp/put.[ab]$$; exit 1' 1 2 15
echo -n 'Summary: '