№ 16. Работа с архивом удаленных файлов
Теперь, когда в домашней папке пользователя появился скрытый каталог с удаленными файлами, пригодился бы сценарий, позволяющий выбирать для восстановления одну из нескольких удаленных версий. Однако эта задача сложна тем, что нам придется предусмотреть все вероятные проблемы: от невозможности найти требуемый файл до обнаружения нескольких копий, соответствующих заданному критерию. Например, если обнаружится несколько совпадений, какую копию должен восстановить сценарий — самую старую или самую новую? Или он должен вывести сообщение об ошибке, указав в нем количество найденных совпадений? Или вывести список версий и предложить пользователю выбрать нужную? Давайте посмотрим, как решаются эти проблемы на практике, изучив сценарий 2.7, в котором приводится сценарий командной оболочки unrm.
Код
Листинг 2.7. Сценарий unrm для восстановления файлов из резервных копий
··#!/bin/bash
··# unrm — отыскивает в архиве удаленных файлов требуемый файл или
··#·· каталог. Если найдено более одного совпадения, выводит список
··#·· результатов поиска, упорядоченных по времени, и предлагает
··#·· пользователю выбрать нужный для восстановления.
··archivedir="$HOME/.deleted-files"
··realrm="$(which rm)"
··move="$(which mv)"
··dest=$(pwd)
··if [! -d $archivedir]; then
····echo "$0: No deleted files directory: nothing to unrm" >&2
····exit 1
··fi
··cd $archivedir
··# Если сценарий запущен без аргументов, просто вывести список
··#·· удаленных файлов.
··if [$# −eq 0]; then
····echo "Contents of your deleted files archive (sorted by date):"
····ls −FC | sed −e 's/\([[: digit: ]][[: digit: ]]\.\)\{5\}//g' \
······-e 's/^/ /’
····exit 0
··fi
··# Иначе принять шаблон для поиска, предложенный пользователем.
··#·· Проверить наличие в архиве нескольких совпадений с шаблоном
··matches="$(ls −d *"$1" 2> /dev/null | wc −l)"
··if [$matches −eq 0]; then
····echo "No match for \"$1\" in the deleted file archive." >&2
····exit 1
··fi
··if [$matches −gt 1]; then
····echo "More than one file or directory match in the archive: "
····index=1
····for name in $(ls −td *"$1")
····do
······datetime="$(echo $name | cut −c1-14 | \
········awk−F. '{ print $5"/"$4" at "$3":"$2":"$1 }')"
······filename="$(echo $name | cut −c16-)"
······if [-d $name]; then
········filecount="$(ls $name | wc −l | sed 's/[^[: digit: ]]//g')"
········echo " $index) $filename (contents = ${filecount} items," \
············ " deleted = $datetime)"
······else
········size="$(ls −sdk1 $name | awk '{print $1}')"
········echo " $index) $filename (size = ${size}Kb, deleted = $datetime)"
······fi
······index=$(($index + 1))
····done
····echo ""
····/bin/echo −n "Which version of $1 should I restore ('0' to quit)? [1]: "
····read desired
····if [! -z "$(echo $desired | sed 's/[[: digit: ]]//g')"]; then
······echo "$0: Restore canceled by user: invalid input." >&2
······exit 1
····fi
····if [${desired:=1} −ge $index]; then
······echo "$0: Restore canceled by user: index value too big." >&2
······exit 1
····fi
····if [$desired −lt 1]; then
······echo "$0: Restore canceled by user." >&2
······exit 1
····fi
····restore="$(ls −td1 *"$1" | sed −n "${desired}p")"
····if [-e "$dest/$1"]; then
······echo "\"$1\" already exists in this directory. Cannot overwrite." >&2
······exit 1
····fi
····/bin/echo −n "Restoring file \"$1\"…"
····$move "$restore" "$dest/$1"
····echo "done."
····/bin/echo −n "Delete the additional copies of this file? [y] "