Введение
Набор для прослушивания должен содержать все запрошенные фрагменты. Если одно преобразование завершилось ошибкой, частичная папка не должна выглядеть готовым набором. Вы улучшите Bash-скрипт: будете готовить файлы в закрытом месте, честно останавливаться при ошибках и публиковать только после успеха всех преобразований.
Здесь есть собственные записи, повреждённая учебная копия и независимый старый набор. Файлы предыдущей работы не используются. Сначала завершите «От одного аудиофрагмента к пакетной обработке» либо знайте изученные там кавычки, параметры FFmpeg, функции, массивы и собственные коды завершения. Вы также примените trap Bash, чтобы очищать только временный каталог самого скрипта.
Не публикуйте незавершённые преобразования
На этом шаге вы сделаете так, чтобы неудачный запуск не публиковал новый набор и оставлял прежнюю работу неизменной.
Начните в Workspace, подготовленном для имён UTF-8. Если относительный путь не найден, вернитесь сюда через cd.
cd /home/labex/project/audio-studio
ls input library archive/previous
input содержит учебные копии трёх записей. В library находятся разрешённые исправные оригиналы. archive/previous — старый набор, который нужно сохранить; notes.txt и scratch-other относятся к другим задачам. Меняйте только свои скрипты, учебные копии и новые экспериментальные или выходные каталоги. Поддерживаются обычные нескрытые файлы непосредственно во входном каталоге с расширением .wav в нижнем регистре: монофонический знаковый 16-битный PCM на 22050 Гц длительностью не менее пяти секунд.
Прочитайте исходный скрипт через cat. Его exit 0 сообщает об успехе даже после ошибки преобразования, а ранний mkdir делает неполный набор видимым.
cat batch.sh
Следующая проба намеренно встретит повреждённую запись. Ожидается ошибка FFmpeg, заканчивающаяся на Invalid data found when processing input. Это ошибка формата файла, а не отсутствие команды и не сетевая проблема.
bash batch.sh input trial-pack 3
printf 'Starter exit: %s\n' "$?"
Он ошибочно сообщает Starter exit: 0. ls trial-pack показывает только успешные преобразования; наличие папки не доказывает полноту.
ls trial-pack
Удалите только этот явно названный одноразовый эксперимент. rm -r рекурсивно удаляет каталог и его содержимое; -- завершает разбор параметров. Команда не затрагивает старый набор, оригиналы или постороннюю работу.
rm -r -- trial-pack
Улучшенный контракт требует новый выходной каталог для каждого запуска. Существующие файлы, каталоги и символические ссылки отклоняются, включая ссылки с отсутствующей целью. Родитель выхода должен существовать, а сам выход — находиться вне входа. Параллельные процессы записи не поддерживаются. Это защита от ошибок преобразования, а не транзакционная гарантия при аварийном завершении или отключении питания.
Промежуточный каталог хранит преобразования до публикации. mktemp -d создаёт закрытый каталог с уникальным именем, заменяя суффикс XXXXXX. Он расположен рядом с окончательным выходом, чтобы последнее перемещение оставалось в одной файловой системе. trap '...' EXIT запускает очистку при завершении скрипта. Одинарные кавычки откладывают раскрытие $stage до этой очистки. rm -rf -- "$stage" удаляет именно этот собственный каталог; никогда не заменяйте его шаблоном вроде /tmp/* или .preview.*.
Остальные операции с путями уточняют контракт. $(command) захватывает текст; || exit 2 останавливает работу при ошибке. realpath -m нормализует ещё не существующую цель, а dirname находит её родителя. Проверка префикса case "$output/" отклоняет выход внутри входного каталога. Кавычки сохраняют буквальные символы входного префикса, а конечный * сопоставляет остаток. mv -T перемещает промежуточный каталог точно под новым именем, а не вкладывает его внутрь другого каталога. Предварительная проверка существования не является блокировкой параллельной записи.
Замените batch.sh полной улучшенной версией. Массив, извлечение имени, кавычки и аргументы FFmpeg работают так же, как в первой пошаговой работе.
cat > batch.sh <<'BASH'
#!/usr/bin/env bash
if [ "$#" -ne 3 ]; then printf 'Usage: batch.sh INPUT OUTPUT SECONDS\n' >&2; exit 2; fi
case "$3" in 1|2|3|4|5) seconds=$3 ;; *) printf 'Use 1 to 5 seconds\n' >&2; exit 2 ;; esac
if [ ! -d "$1" ]; then printf 'Input directory missing\n' >&2; exit 2; fi
if [ -e "$2" ] || [ -L "$2" ]; then printf 'Output already exists\n' >&2; exit 2; fi
input=$(realpath -- "$1") || exit 2
output=$(realpath -m -- "$2") || exit 2
parent=$(dirname -- "$output")
if [ ! -d "$parent" ]; then printf 'Output parent missing\n' >&2; exit 2; fi
case "$output/" in "$input/"*) printf 'Output must be outside input\n' >&2; exit 2 ;; esac
shopt -s nullglob
files=("$input"/*.wav)
if [ "${#files[@]}" -eq 0 ]; then printf 'No WAV inputs\n' >&2; exit 1; fi
stage=$(mktemp -d "$parent/.preview.XXXXXX") || exit 1
trap 'rm -rf -- "$stage"' EXIT
for source in "${files[@]}"; do
name=${source##*/}
if ! ffmpeg -nostdin -v error -i "$source" -t "$seconds" -c:a pcm_s16le "$stage/$name"; then
printf 'Could not convert: %s\n' "$name" >&2
exit 1
fi
done
if ! mv -T -- "$stage" "$output"; then exit 1; fi
printf 'Published %s previews\n' "${#files[@]}"
BASH
Ещё раз попробуйте те же повреждённые учебные входы. Ошибка намеренная; пока ничего не восстанавливайте.
bash batch.sh input previews 3
printf 'Protected batch exit: %s\n' "$?"
Ожидаются Could not convert: zz Evening.wav и Protected batch exit: 1. Явная ветвь ошибки останавливает запуск. previews не должен существовать, а временный промежуточный каталог уже должен быть удалён.
ls -a включает скрытые имена, поэтому позволяет найти оставленные промежуточные каталоги .preview.. При этом scratch-other должен оставаться на месте, а его содержимое — быть неизменным.
ls -a
Запустите проверку шага. Она исполняет ваш неизменённый скрипт в одноразовых каталогах и не восстанавливает учебный вход и не создаёт ваш настоящий набор.
Восстановите учебную копию и опубликуйте набор
На этом шаге вы определите повреждённую запись, восстановите только её разрешённую учебную копию и опубликуете полный набор своим скриптом.
Начните в Workspace. FFmpeg может проверить запись, не создавая другой медиафайл: -f null - выбирает выход, который отбрасывает декодированные отсчёты. Успешное декодирование подтверждает читаемое аудио, а повреждённый файл возвращает ненулевой код. Здесь это применяется только к названной учебной копии курса.
ffmpeg -nostdin -v error -i "input/zz Evening.wav" -f null -
printf 'Decode exit: %s\n' "$?"
Ожидаются ошибка формата и ненулевой код. Исправный одноимённый файл есть в library. cp -- копирует этот оригинал поверх повреждённой учебной копии; оба пути в кавычках точно указывают файл. Саму библиотеку не меняйте.
cp -- "library/zz Evening.wav" "input/zz Evening.wav"
ffmpeg -nostdin -v error -i "input/zz Evening.wav" -f null -
printf 'Decode exit: %s\n' "$?"
Теперь ожидается ноль. Если имя набрано неверно, посмотрите ls library и исправьте его; сбрасывать среду не нужно. Запустите полную обработку с восстановленным входом.
bash batch.sh input previews 3
Ожидается Published 3 previews. Переключитесь в Listening Room и обновите страницу. Воспроизведите каждый фрагмент под Your listening pack, переместитесь внутри каждого и скачайте один. Все должны длиться три секунды и начинаться с соответствующей записи. Страница читает только previews; удаление или повреждение фрагмента не заставит её незаметно воспроизвести оригинал из библиотеки. Вернитесь в Workspace.
Наконец, ещё раз попробуйте существующий выход. Этот намеренный отказ защищает полный набор.
bash batch.sh input previews 3
printf 'Existing output exit: %s\n' "$?"
Ожидаются Output already exists и ненулевой код. Сохраните результат. Для другого набора позже выберите новое имя и длительность от одной до пяти секунд; родительский каталог должен уже существовать. Оригиналы, старый набор, заметки и посторонний каталог должны оставаться неизменными.
Резюме
Вы разделили подготовку и публикацию, честно вернули ошибки и очистили один собственный промежуточный каталог через обработчик EXIT. Вы определили и восстановили повреждённую учебную запись, затем опубликовали полный набор пригодных для воспроизведения фрагментов, сохранив прежнюю работу. Задание применяет те же инструменты к другой коллекции.



