Введение
Field Notes знает, какие материалы повреждены или отсутствуют. Теперь организаторам нужна процедура восстановления: получить только эти материалы, сравнить байты с независимым эталоном и публиковать каждую замену лишь после успешной проверки. Источник может вернуть HTTP-ошибку или полностью успешный HTTP-ответ с неверным документом.
Работа начинается с собственного подготовленного пакета. Нужны знания SHA256, целых строк, подстановки команд и полных имён из предыдущей работы; файлы из предыдущей VM не требуются. Workspace и Download Desk используют один контейнер. Оригинальный синтетический PDF и curl подготовлены. Время оценено автором с учётом чтения и устранения ошибок.
Скачайте кандидат перед заменой
На этом шаге вы сохраните и проверите настоящий раздаточный материал в отдельном учебном каталоге.
Начните в Workspace, подготовленном для текста UTF-8. Если относительное имя не найдено, используйте этот абсолютный путь. pwd и ls pack помогают отличить неверный каталог от опечатки в имени.
cd /home/labex/project/download-desk
Доверенный манифест находится в /opt/labex/download-pack-state/expected.sha256. Формат тот же, что в первой работе: 64 шестнадцатеричных символа в нижнем регистре, два пробела и полное имя без уровней каталогов. Он предоставлен независимо, доступен для чтения, непустой и заканчивается переводом строки. Имена используют печатный ASCII и могут содержать пробелы; косая и обратная косая черта, CR, LF, табуляция и имена . и .. не поддерживаются. Используйте настоящие каталоги без ссылок в цепочке родителей. Ожидаемый элемент должен отсутствовать или быть обычным локальным файлом; ссылки и объекты-каталоги отклоняются. Не редактируйте эталон и источник. Совпадение SHA256 доказывает соответствие этому доверенному эталону, а не личность издателя.
cat /opt/labex/download-pack-state/expected.sha256
Подготовленный каталог trial предназначен для экспериментов и отделён от pack организаторов. mktemp создаёт уникальный пустой файл по шаблону, заканчивающемуся символами X, и выводит путь. Сохранив его в candidate, вы сможете пользоваться им в этой сессии Workspace. При новом подключении переменные оболочки могут потеряться; начните эту учебную последовательность заново, а не угадывайте старое значение.
candidate=$(mktemp trial/.incoming.XXXXXX)
curl отправляет HTTP-запрос. У параметров здесь разные задачи:
--getотправляет GET-запрос, а--data-urlencode 'name=Workshop card.txt'безопасно кодирует имя файла как параметр запроса. Кавычки защищают аргументы оболочки; URL-кодирование обрабатывает пробелы внутри запроса.--failдаёт ненулевой код завершения при HTTP-ошибках вроде 503. Неверное содержимое при HTTP 200 он не обнаруживает.--silent --show-errorскрывает индикаторы прогресса, сохраняя сообщения об ошибках.--max-time 8ограничивает всю передачу восемью секундами.--output "$candidate"записывает только во временный кандидат.127.0.0.1:8080— подготовленный локальный источник в том же контейнере;/goodвозвращает правильные байты.
curl --fail --silent --show-error --get --data-urlencode 'name=Workshop card.txt' --max-time 8 --output "$candidate" http://127.0.0.1:8080/good
printf 'Download exit: %s\n' "$?"
Ожидается Download exit: 0. Если URL введён неверно, curl может сообщить об ошибке соединения или HTTP-отказе. Исправьте адрес выше, удалите только текущий кандидат командой rm -- "$candidate" и повторите действия начиная с mktemp. -- завершает параметры; точное значение переменной указывает на ваш собственный эксперимент.
Возьмите ожидаемый хеш раздаточного материала из его строки в доверенном манифесте. Он равен следующему значению, независимому от кандидата:
expected=a9986fb03d5ca72e42753d0ddd11dce7794b0e5a8b253dd4cd356825ca6d0583
Канал | соединяет стандартный вывод команды со стандартным вводом следующей. Следующий printf создаёт запись контрольной суммы для кандидата. sha256sum --check читает её, а && запускает mv только при успешной проверке. mv -- переименовывает проверенный кандидат в окончательный учебный файл. При повторении эксперимента его можно заменить; правила выборочного восстановления организаторов относятся к pack.
printf '%s %s\n' "$expected" "$candidate" | sha256sum --check && mv -- "$candidate" "trial/Workshop card.txt"
Ожидается строка, заканчивающаяся на : OK. Если указано FAILED, не перемещайте кандидат: удалите только его и повторите исправленную загрузку. Теперь прочитайте проверенный материал:
cat "trial/Workshop card.txt"
REPAIR DESK: EAST HALL
Вы не допустили непроверенную загрузку к окончательному имени файла. Далее вы примените тот же порядок ко всему пакету.
Восстанавливайте выборочно и продолжайте после ошибок
На этом шаге вы передадите процедуре три аргумента и проверите как полезный результат, так и границу защиты при сбоях.
Начните в Workspace в /home/labex/project/download-desk. Контракт вызова — bash repair-pack.sh MANIFEST SOURCE_URL PACK_DIRECTORY. Это самостоятельная программа Bash, использующая эти аргументы и установленные команды, без соседних вспомогательных файлов. Сначала она должна классифицировать фактические байты каждого элемента. Совпадающий элемент не вызывает загрузку и сохраняет байты, режим, владельца и mtime. Та же защита действует для постороннего файла pack/notes.txt. Скачивать разрешено только отсутствующие или несовпадающие элементы, не более одного раза каждый за вызов. Пустой файл с совпадающим хешем исправен. Второй вызов для полного пакета должен выполнить ноль запросов на загрузку и сохранить всё состояние пакета.
Каждый кандидат размещается рядом с целевым файлом и удаляется после обычного успеха или сообщённой ошибки. Публикация выполняется для каждого файла отдельно: проверенная замена может остаться, если следующий элемент завершится ошибкой. Неудачные или неверные кандидаты никогда не заменяют целевой файл. Это не транзакция для всего пакета и не гарантия при параллельной записи, потере питания или любом возможном завершении процесса. Используйте только пути курса и избегайте параллельных изменений.
Разбор строк и извлечение хеша используют синтаксис предыдущей работы. Следующие дополнительные элементы защищают замену:
[ -r "$manifest" ]проверяет доступность для чтения;[ -s "$manifest" ]требует непустой манифест.!инвертирует проверку.||означает ИЛИ между проверками либо запускает ветку ошибки после неудачной команды.&&здесь означает И. Фигурные скобки объединяют связанные проверки без новой подоболочки.[ -d "$pack" ]проверяет каталог.[ -L "$target" ]обнаруживает даже ссылку с отсутствующей целью;-eпроверяет существование цели, а-f— обычный файл. Отказ от ссылок и других типов объектов доmvпредотвращает переход по ссылке на источник или случайное перемещение кандидата внутрь каталога.temporary=начинает с пустой переменной.trap '...' EXITрегистрирует очистку при выходе из скрипта. Одинарные кавычки откладывают раскрытие до очистки.-nозначает непустую переменную; удаляется только файл, созданный самим скриптом.rm -fспокойно принимает уже удалённый кандидат;--завершает параметры.continueпереходит к следующей строке манифеста.exit 1сообщает об ошибке.>&2отправляет объяснение в стандартный поток ошибок, а не в обычный вывод. Обнулениеtemporaryпосле успешного переименования не позволяет очистке затронуть опубликованный файл.
Сохраните полный скрипт с помощью буквального here-document из первой работы:
cat > repair-pack.sh <<'BASH'
#!/usr/bin/env bash
manifest=$1
base=$2
pack=$3
if [ ! -r "$manifest" ] || [ ! -s "$manifest" ]; then
printf 'A readable nonempty trusted manifest is required.\n' >&2
exit 1
fi
if [ ! -d "$pack" ] || [ -L "$pack" ]; then
printf 'A real pack directory is required.\n' >&2
exit 1
fi
temporary=
trap 'if [ -n "$temporary" ]; then rm -f -- "$temporary"; fi' EXIT
while IFS= read -r line; do
expected=${line:0:64}
name=${line:66}
target=$pack/$name
if [ -L "$target" ] || { [ -e "$target" ] && [ ! -f "$target" ]; }; then
printf 'Expected a regular file or absent member: %s\n' "$name" >&2
exit 1
fi
if [ -f "$target" ]; then
actual=$(sha256sum -- "$target")
actual=${actual%% *}
if [ "$actual" = "$expected" ]; then
printf 'Keep: %s\n' "$name"
continue
fi
fi
temporary=$(mktemp "$pack/.repair.XXXXXX") || exit 1
if ! curl --fail --silent --show-error --get --data-urlencode "name=$name" --max-time 8 --output "$temporary" "$base"; then
printf 'Download failed: %s\n' "$name" >&2
exit 1
fi
actual=$(sha256sum -- "$temporary")
actual=${actual%% *}
if [ "$actual" != "$expected" ]; then
printf 'Checksum mismatch: %s\n' "$name" >&2
exit 1
fi
mv -- "$temporary" "$target" || exit 1
temporary=
printf 'Repaired: %s\n' "$name"
done < "$manifest"
BASH
Очистка получает только ваш точный временный путь и не удаляет чужие файлы. Допустимы другое безопасное временное имя или эквивалентный цикл. Проверка оценивает поведение, а не точное написание команд или текст вывода Keep:.
Проверьте успешный HTTP-ответ с неверным содержимым
Контролируемая конечная точка /html возвращает HTML-страницу ошибки с HTTP 200. Это настоящий ответ, а не имитация статуса curl. Следующая команда должна завершиться ошибкой, не заменив существующий повреждённый материал:
bash repair-pack.sh /opt/labex/download-pack-state/expected.sha256 http://127.0.0.1:8080/html pack
printf 'Repair exit: %s\n' "$?"
Ожидаются Repair exit: 1 и Checksum mismatch: Workshop card.txt. PDF уже был правильным, поэтому пропущен. Неверный кандидат удалён; одного HTTP-успеха недостаточно для публикации. ls -a показывает и скрытые имена, позволяя убедиться, что кандидат .repair.* не остался:
ls -a pack
Теперь используйте правильный источник. Скрипт исправит раздаточный материал и отсутствующую карту, сохранив PDF, пустой файл благодарностей и личную заметку:
bash repair-pack.sh /opt/labex/download-pack-state/expected.sha256 http://127.0.0.1:8080/good pack
(cd pack && sha256sum --check /opt/labex/download-pack-state/expected.sha256)
У каждого перечисленного элемента должно быть OK. Переключитесь на Download Desk, обновите страницу и откройте PDF и карту. На карте указан восточный вход. Выберите Download рядом с PDF и откройте сохранённый файл в браузерном просмотрщике. Оба действия используют локальный пакет, без подстановки из источника. Для фиксированных страниц PDF используйте встроенное масштабирование. Вернитесь в Workspace.
Повторите без новой загрузки
Подготовленный источник записывает по одной строке в requests.jsonl на каждый фактический запрос материала, включая идентификацию процесса источника. Каждое событие полностью записывается в файл до наблюдения. wc -l < FILE считает строки, перенаправляя файл в команду; он не запрашивает материал. Прочитайте счётчик, повторно запустите процедуру и прочитайте его ещё раз:
wc -l < /opt/labex/download-pack-state/requests.jsonl
bash repair-pack.sh /opt/labex/download-pack-state/expected.sha256 http://127.0.0.1:8080/good pack
wc -l < /opt/labex/download-pack-state/requests.jsonl
Оба числа должны совпасть. Все четыре элемента должны сохраниться. Повторная загрузка всего пакета тратит запросы и может изменить режимы или временные метки правильных файлов даже при одинаковых итоговых хешах.
Испытайте ошибки передачи вне готового пакета
mkdir -p при необходимости создаёт каталог эксперимента. Он не сбрасывает его содержимое. Оставьте готовый пакет организаторов нетронутым:
mkdir -p trial/fault-test
Контролируемая точка /error возвращает HTTP 503. Ожидаются сообщение curl с 503 и ненулевой код скрипта:
bash repair-pack.sh /opt/labex/download-pack-state/expected.sha256 http://127.0.0.1:8080/error trial/fault-test
printf 'HTTP-error exit: %s\n' "$?"
Ожидается HTTP-error exit: 1. Контролируемая точка /partial закрывает соединение после передачи лишь части объявленного тела. Ожидаются ошибка curl 18 об оставшихся байтах и вновь отсутствие опубликованного кандидата:
bash repair-pack.sh /opt/labex/download-pack-state/expected.sha256 http://127.0.0.1:8080/partial trial/fault-test
printf 'Partial-transfer exit: %s\n' "$?"
Ожидается Partial-transfer exit: 1. Ошибка соединения, HTTP-отказ и неверное содержимое при HTTP 200 — разные наблюдения; все они предотвращают непроверенную замену. Восстановите эксперимент с той же правильной конечной точкой и теми же аргументами:
bash repair-pack.sh /opt/labex/download-pack-state/expected.sha256 http://127.0.0.1:8080/good trial/fault-test
Если в пути манифеста или каталога опечатка, скрипт назовёт нужный объект и завершится с ненулевым кодом. Перед повтором проверьте pwd, ls и абсолютный путь эталона. При синтаксической ошибке в сохранённом скрипте замените только repair-pack.sh полным here-document выше. Не удаляйте пакет организаторов ради исправления опечатки.
Итоговая проверка читает фактический пакет и сохраняемые объекты. Она также запускает ваш неизменённый скрипт на изолированных пакетах с другими именами и контролируемыми HTTP-сбоями, включая существующую повреждённую цель и отсутствующий допустимый пустой файл. Эти запросы делает ваш скрипт, а не загрузка оценщика, восполняющая недостающие доказательства. Повторная проверка не восстанавливает и не сбрасывает вашу фактическую работу.
Резюме
Вы скачали файл-кандидат, проверили SHA256 перед публикацией и создали многократно используемый скрипт выборочного восстановления. Настоящие HTTP-ошибки, успешные ответы с неверным содержимым и оборванные тела ответов не попали под окончательные имена файлов. Правильные файлы и личные заметки сохранены, а второй запуск для полного пакета обошёлся без загрузок.



