소개
미리듣기 묶음에는 요청한 모든 클립이 있어야 합니다. 변환 하나가 실패했을 때 불완전한 폴더가 완성된 묶음처럼 보여서는 안 됩니다. Bash 스크립트를 개선하여 파일을 비공개로 준비하고, 오류에 정확히 멈추며, 모든 변환이 성공한 뒤에만 공개합니다.
이 실습에는 자체 녹음, 손상된 연습용 복사본, 별개의 이전 묶음이 있습니다. 앞선 실습의 파일을 사용하지 않습니다. 먼저 “하나의 미리듣기를 일괄 처리로 확장하기”를 완료하거나, 거기서 다룬 따옴표, FFmpeg 옵션, 함수, 배열, 명령 자체의 종료 상태를 알고 있어야 합니다. Bash의 trap도 사용하여 스크립트 자신이 만든 임시 디렉터리만 정리합니다.
미완성 변환 결과를 공개하지 않기
이 단계에서는 변환에 실패한 일괄 처리가 새로운 출력을 공개하지 못하게 하고, 기존 작업은 변경 없이 유지합니다.
UTF-8 파일명에 맞게 준비된 Workspace에서 시작하세요. 상대 경로를 찾을 수 없다면 cd로 여기로 돌아옵니다.
cd /home/labex/project/audio-studio
ls input library archive/previous
input에는 세 녹음의 연습용 복사본이 있습니다. 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 아래 각 클립을 재생하고, 재생 위치를 옮기고, 하나를 다운로드합니다. 각각 3초이며 대응하는 녹음의 시작 부분이어야 합니다. 이 페이지는 previews만 읽습니다. 미리듣기를 삭제하거나 손상시켜도 라이브러리 원본으로 몰래 대체해 재생할 수 없습니다. Workspace로 돌아옵니다.
마지막으로 기존 출력을 다시 시도하세요. 이 의도된 거부가 완전한 묶음을 보호합니다.
bash batch.sh input previews 3
printf 'Existing output exit: %s\n' "$?"
Output already exists와 0이 아닌 상태가 나와야 합니다. 이 출력은 보관하세요. 나중에 다른 묶음을 만들 때는 새로운 이름과 1~5초 길이를 사용하고, 부모 디렉터리를 미리 준비합니다. 원본 녹음, 이전 묶음, 메모, 무관한 디렉터리는 변경 없이 남아야 합니다.
요약
준비와 공개를 분리하고, 실패를 정확히 반환하며, EXIT trap으로 자신이 만든 스테이징 디렉터리 하나만 정리했습니다. 손상된 연습용 녹음을 진단하고 복원한 뒤, 이전 작업을 유지하면서 완전하고 재생 가능한 묶음을 공개했습니다. 챌린지는 같은 도구를 다른 녹음 모음에 적용합니다.



