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

如何修改Bash脚本实现仅分割M4B文件的第2至第6章节

如何修改Bash脚本实现仅分割M4B文件的第2至第6章节

你的脚本出现语法错误的核心原因是拿到的chapter变量是章节名称(比如"Opening Credits")而不是章节数字,导致数值比较((chapter >=2 && chapter <=6))无法执行。下面我会帮你修正脚本的核心问题,同时优化循环逻辑避免重复处理文件。

关键问题分析

原来的脚本中,read -r _ _ chapter这一行读取的是章节的名称而非数字,当你用数值比较符判断字符串时,Bash就会抛出syntax error。另外,内层的for f in *.m4b循环和外层的参数处理循环重复,会导致文件被多次处理。

修改后的完整脚本

#!/bin/bash
# 仅分割M4B文件的第2至第6章节,输出为MP3
# 运行方式: bash m4b-split.sh *.m4b

currentdir=$(pwd) # 获取当前目录

while [ $# -gt 0 ]; do
    f="$1"
    # 跳过非M4B文件
    if [[ "$f" != *.m4b ]]; then
        echo "跳过非M4B文件: $f"
        shift
        continue
    fi

    fn=$(basename "$f" | cut -d'.' -f1) # 获取不带扩展名的文件名
    echo "正在处理文件: ($fn)"
    splitdirname="$currentdir/final-split-$fn" # 生成存储分割文件的子目录
    mkdir -p "$splitdirname" # 创建目录(如果不存在)

    # 用ffmpeg提取章节信息到临时文件
    ffmpeg -i "$f" 2> tmp.txt

    # 逐行解析临时文件中的章节信息
    while read -r line; do
        if [[ "$line" == Chapter* ]]; then
            # 从Chapter行提取章节数字(比如从"Chapter #0:0: start ..."中提取0)
            chapter_num=$(echo "$line" | sed -E 's/Chapter #([0-9]+):.*/\1/')
            # 提取开始和结束时间
            start=$(echo "$line" | awk '{print $4}')
            end=$(echo "$line" | awk '{print $6}' | sed 's/,$//') # 去掉end后面的逗号

            # 跳过Metadata行
            read -r
            # 读取章节名称
            read -r _ _ chapter_name

            # 仅处理第2至第6章
            if (( chapter_num >= 2 && chapter_num <= 6 )); then
                # 生成输出文件名(替换空格为短横线避免问题)
                output_file="$splitdirname/${chapter_num}-${chapter_name// /-}-${fn}.mp3"
                echo "正在分割章节 $chapter_num: $chapter_name -> $output_file"
                
                # 调用ffmpeg执行分割和转码
                ffmpeg -vsync 2 -i "$f" -ss "$start" -to "$end" \
                    -metadata title="${chapter_num}. ${chapter_name}" \
                    -metadata track="$chapter_num" \
                    -vn -ar 22050 -ac 1 -ab 128k -f mp3 "$output_file" < /dev/null
            fi
        fi
    done < tmp.txt

    rm tmp.txt # 清理临时文件
    shift # 处理下一个传入的文件
done

核心修改点说明

  1. 修复循环逻辑
    去掉了多余的内层for f in *.m4b循环,直接处理你传入的每个参数文件,同时增加了非M4B文件的跳过逻辑,避免无效处理。

  2. 正确提取章节数字
    通过sed -E 's/Chapter #([0-9]+):.*/\1/'从Chapter行本身提取章节编号,确保chapter_num是纯数字,这样数值比较((chapter_num >=2 && chapter_num <=6))就能正常执行。

  3. 优化时间参数处理
    直接从Chapter行提取start和end时间,并通过sed 's/,$//'去掉end后面的逗号,避免ffmpeg解析时间参数时报错。

  4. 文件名和元数据优化
    保留章节名称用于输出文件名和MP3的标题元数据,同时把名称中的空格替换为短横线,避免文件名出现空格引发的问题。

  5. 临时文件清理
    确保每次处理完一个文件后都删除临时文件tmp.txt,避免残留数据影响后续处理。

现在运行bash m4b-split.sh *.m4b就可以只分割每个M4B文件的第2到第6章节了。

备注:内容来源于stack exchange,提问作者Rick T

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.17 13:14:38