You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

循环结束后删除指定目录的Bash脚本问题求助

问题分析

你的脚本存在两个核心问题:

  1. 变量作用域丢失:find | while read 会创建子shell,循环内定义的ORIG_DIR、ALAC_DIR变量在循环结束后会失效,导致循环外的rm -rf "$ORIG_DIR"无法识别正确路径。
  2. 目录删除时机错误:若在循环内每个文件处理完就删除目录,会导致同一目录下的后续文件处理失败;而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
关键改动说明
  1. 避免子shell:用< <(find ...)替代管道,让循环在当前shell执行,变量可被后续代码正常访问。
  2. 源目录去重收集:用关联数组orig_dirs存储所有源目录,避免重复执行删除操作。
  3. 安全删除ALAC_DIR:使用rmdir而非rm -rf,仅删除空目录,防止误删已生成ALAC文件的目录,同时通过2>/dev/null屏蔽非空目录的错误提示。
  4. 延迟删除源目录:等所有文件转码完成后,遍历收集到的源目录,确认为空后再删除,避免提前删除导致后续文件处理失败。

内容的提问来源于stack exchange,提问作者ThePix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 17:15:54