はじめに
試聴パックには、求められたすべてのクリップがそろっている必要があります。変換が1つ失敗したとき、不完全なフォルダーが完成品に見えてはいけません。Bash スクリプトを改善し、ファイルを非公開で準備し、エラー時には正しく停止し、すべての変換が成功した場合だけ公開します。
このラボには独自の録音、壊れた練習用コピー、無関係の古いパックがあります。前のラボのファイルは使いません。先に「1つの試聴から一括処理へ」を終えるか、そこで扱う引用符、FFmpeg オプション、関数、配列、コマンド自身の終了ステータスを理解していてください。さらに Bash の trap を使い、スクリプト自身の一時ディレクトリだけを片付けます。
未完了の変換結果を公開しない
このステップでは、変換に失敗した一括処理が新しい出力を公開しないようにし、既存の作業は変更せずに保ちます。
UTF-8 のファイル名に対応した Workspace から始めます。相対パスが見つからなければ、cd でここへ戻ってください。
cd /home/labex/project/audio-studio
ls input library archive/previous
input には3つの録音の練習用コピーがあります。library には使用が許可された正常な原本があります。archive/previous は保管すべき古い試聴パックで、notes.txt と scratch-other は別の作業に属します。変更してよいのは自分のスクリプト、練習用コピー、新しい実験用・出力用ディレクトリだけです。対応する入力は、入力ディレクトリ直下の隠しファイルではない通常ファイルで、小文字の .wav が付き、22050 Hz の符号付き16ビット・モノラル PCM、5秒以上のものです。
cat で初期スクリプトを読みます。末尾の exit 0 は変換に失敗しても成功を報告し、早すぎる mkdir は不完全なパックを見える状態にします。
cat batch.sh
次の試行では、意図的に壊れた録音に遭遇します。Invalid data found when processing input で終わる FFmpeg エラーが出るはずです。これはファイル形式のエラーであり、コマンドがない、またはネットワークに問題があるという意味ではありません。
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 - は、デコードしたサンプルを捨てる出力先を選びます。正常にデコードできれば読める音声だと分かり、破損ファイルなら0以外を返します。ここでは指定された教材の練習用コピーだけに使います。
ffmpeg -nostdin -v error -i "input/zz Evening.wav" -f null -
printf 'Decode exit: %s\n' "$?"
形式エラーと0以外のステータスになるはずです。同名の正常なファイルが 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' "$?"
今度は0になるはずです。名前を間違えたら ls library で確認して修正します。環境をリセットする必要はありません。復元した入力で完全な一括処理を実行します。
bash batch.sh input previews 3
Published 3 previews と表示されるはずです。Listening Room に切り替えて再読み込みします。Your listening pack の各クリップを再生し、位置を変えて聴き、1つをダウンロードしてください。それぞれ3秒で、対応する録音の先頭から始まります。ページが読むのは previews だけです。試聴を削除・破損させても、ひそかにライブラリ原本を再生することはできません。Workspace に戻ります。
最後に、もう一度既存の出力を試します。この意図的な拒否が完全なパックを守ります。
bash batch.sh input previews 3
printf 'Existing output exit: %s\n' "$?"
Output already exists と0以外のステータスになるはずです。この出力は残してください。後で別のパックを作る際は新しい名前と1〜5秒の長さを選び、親ディレクトリをあらかじめ用意します。原本、古いパック、メモ、無関係のディレクトリは変更されていてはいけません。
まとめ
準備と公開を分け、失敗を正しく返し、EXIT trap で自分のステージングディレクトリ1つだけを片付けました。壊れた練習用録音を診断・復元し、これまでの作業を保ったまま、完全で再生可能なパックを公開しました。チャレンジでは、同じ道具を別のコレクションに応用します。



