循环结束后删除指定目录的Bash脚本问题求助
问题分析
你的脚本存在两个核心问题:
- 变量作用域丢失:
find | while read会创建子shell,循环内定义的ORIG_DIR、ALAC_DIR变量在循环结束后会失效,导致循环外的rm -rf "$ORIG_DIR"无法识别正确路径。 - 目录删除时机错误:若在循环内每个文件处理完就删除目录,会导致同一目录下的后续文件处理失败;而MP3对应的
ALAC_DIR需要确保无生成文件后再删除,当前逻辑会提前执行删除操作。
解决方案
我们可以通过以下方式修正:
- 用进程替换替代管道,避免子shell导致的变量丢失;
- 先收集所有待处理的源目录,等所有文件转码完成后批量删除;
- 针对MP3文件,转码成功后删除空的
ALAC_DIR(因MP3不会生成ALAC文件,仅创建了空目录)。
修改后的脚本如下:
#!/bin/bash SOURCE_DIR="$(cd "$(dirname "${dirs[0]}")"; pwd)/$(basename "${dirs[0]}")" SOURCE_DIR=$(dirname "$SOURCE_DIR/temp") # 修复 . 和 ./ 的路径问题 HIRES_DIR="$(cd "$(dirname "${dirs[1]}")"; pwd)/$(basename "${dirs[1]}")" HIRES_DIR=$(dirname "$HIRES_DIR/temp") LORES_DIR="$(cd "$(dirname "${dirs[2]}")"; pwd)/$(basename "${dirs[2]}")" LORES_DIR=$(dirname "$LORES_DIR/temp") # 收集所有需要处理的源目录(关联数组去重) declare -A orig_dirs while read -r FILE; do orig_dirs["$(dirname "$FILE")"]=1 done < <(find "$SOURCE_DIR" \( -iname '*.flac' -o -iname '*.mp3' \) -type f) # 处理每个文件的转码逻辑 while read -r FILE; do ORIG_DIR=$(dirname "$FILE") BASE=$(basename "$FILE") BASE=${BASE%.*} AAC_DIR=${ORIG_DIR/$SOURCE_DIR/$LORES_DIR} ALAC_DIR=${ORIG_DIR/$SOURCE_DIR/$HIRES_DIR} mkdir -p "$AAC_DIR" "$ALAC_DIR" AAC_FILE="$AAC_DIR/$BASE.m4a" ALAC_FILE="$ALAC_DIR/$BASE.m4a" if [[ ! -f "$AAC_FILE" && "$FILE" == *.flac ]]; then # FLAC转AAC和ALAC,确保转码成功再执行下一步 if ffmpeg -hide_banner -i "$FILE" -c:v copy -b:a 256k -c:a aac "$AAC_FILE" </dev/null; then ffmpeg -hide_banner -i "$FILE" -c:v copy -c:a alac "$ALAC_FILE" </dev/null fi elif [[ ! -f "$AAC_FILE" && "$FILE" == *.mp3 ]]; then # MP3转AAC,成功后删除空的ALAC_DIR if ffmpeg -hide_banner -i "$FILE" -c:v copy -b:a 256k -c:a aac "$AAC_FILE" </dev/null; then # rmdir仅删除空目录,避免误删有内容的目录,忽略非空错误提示 rmdir "$ALAC_DIR" 2>/dev/null fi fi done < <(find "$SOURCE_DIR" \( -iname '*.flac' -o -iname '*.mp3' \) -type f) # 所有文件处理完成后,删除空的源目录 for dir in "${!orig_dirs[@]}"; do # 检查目录是否为空,确保所有文件都已处理完成 if [ -z "$(ls -A "$dir")" ]; then rm -rf "$dir" fi done
关键改动说明
- 避免子shell:用
< <(find ...)替代管道,让循环在当前shell执行,变量可被后续代码正常访问。 - 源目录去重收集:用关联数组
orig_dirs存储所有源目录,避免重复执行删除操作。 - 安全删除ALAC_DIR:使用
rmdir而非rm -rf,仅删除空目录,防止误删已生成ALAC文件的目录,同时通过2>/dev/null屏蔽非空目录的错误提示。 - 延迟删除源目录:等所有文件转码完成后,遍历收集到的源目录,确认为空后再删除,避免提前删除导致后续文件处理失败。
内容的提问来源于stack exchange,提问作者ThePix
相关产品推荐
相关产品推荐

