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

Bash脚本行读取异常:MPV视频剪辑脚本故障求助

基于Bash的MPV视频剪辑脚本问题修复

我编写了一款基于Bash的MPV视频剪辑脚本,通过MPV播放器截图文件名中的时间码完成视频切割。选择MPV是因其处理大体积视频速度快,按s键即可标记剪辑入点、出点(截图),且未找到同类Bash脚本,仅见Lua和Java版本。

原脚本代码

#!/bin/bash

clear

DATE=$(date +"%Y%m%d_%H%M%S")

x-terminal-emulator  -geometry 50x20+3100+0 -e "bash -c 'while true; do clear;ls *.jpg;sleep 1;done &'"

rm *.jpg CUT*.mp4 cutLines.* cutMerge.*

mpv --screenshot-template="~/%F-(%P)-%03n" "$1"

echo
read -p "--- Hit ENTER to CUT ---"
echo

ls *.jpg | cut -c 24-35 > cutLines.txt

IFS=$'\n'
while IFS= read -r ONE; do read -r TWO
        echo " Making cut for duration: $ONE - $TWO stored as: CUT_${ONE}.mp4"
    ffmpeg -nostdin -loglevel quiet -ss "${ONE}" -to "${TWO}" -i "${1}" -c copy CUT_"${ONE}".mp4
        echo CUT_"${ONE}".mp4 >> cutMerge.tmp
done < cutLines.txt

cat cutMerge.tmp | sed "s/^/file '/" |sed "s/$/'/" > cutMerge.txt

ffmpeg -f concat -safe 0 -i cutMerge.txt -c copy CUTmerge_"$DATE".mp4

存在的问题

脚本可正常生成剪辑片段,但read命令读取行数据不完整,根源在于:

  • 用cut -c 24-35固定字符位置截取时间码的方式不可靠,文件名长度变化会导致截取内容错误;
  • 循环中连续read两行的逻辑依赖截图数量为偶数,且未处理行读取失败的情况。

修复方案

核心改进点

  1. 可靠提取时间码:利用MPV截图文件名的格式([文件名]-(时间码)-[序号].jpg),用正则匹配提取括号内的时间码,避免固定字符位置的误差;
  2. 安全处理成对时间码:先将所有时间码存入数组,再遍历数组两两分组处理,确保入点和出点正确配对。

修复后的脚本

#!/bin/bash

clear

DATE=$(date +"%Y%m%d_%H%M%S")

# 启动实时显示截图的终端窗口
x-terminal-emulator -geometry 50x20+3100+0 -e "bash -c 'while true; do clear; ls -1 *.jpg 2>/dev/null; sleep 1; done'" &
TERM_PID=$!

# 清理旧文件
rm -f *.jpg CUT*.mp4 cutLines.* cutMerge.*

# 启动MPV并设置截图模板
mpv --screenshot-template="~/%F-(%P)-%03n" "$1"

# 关闭实时显示的终端窗口
kill $TERM_PID 2>/dev/null

echo
read -p "--- Hit ENTER to CUT ---"
echo

# 提取所有截图中的时间码(匹配括号内的HH:MM:SS.sss格式)
ls -1 *.jpg | sed -E 's/.*\(([0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3})\).*/\1/' > cutLines.txt

# 将时间码存入数组
mapfile -t timestamps < cutLines.txt

# 检查时间码数量是否为偶数
if (( ${#timestamps[@]} % 2 != 0 )); then
    echo "错误:截图数量为奇数,请确保入点和出点成对!"
    exit 1
fi

# 两两分组处理时间码
> cutMerge.tmp
for ((i=0; i<${#timestamps[@]}; i+=2)); do
    start=${timestamps[$i]}
    end=${timestamps[$i+1]}
    output="CUT_${start//:/_}.mp4"  # 替换时间码中的冒号避免文件名问题
    
    echo "正在剪辑片段:$start - $end,保存为:$output"
    ffmpeg -nostdin -loglevel quiet -ss "$start" -to "$end" -i "$1" -c copy "$output"
    
    echo "$output" >> cutMerge.tmp
done

# 生成ffmpeg concat所需的文件列表
sed "s/^/file '/; s/$/'/" cutMerge.tmp > cutMerge.txt

# 合并所有剪辑片段
ffmpeg -f concat -safe 0 -i cutMerge.txt -c copy "CUTmerge_${DATE}.mp4"

echo "剪辑完成,合并文件:CUTmerge_${DATE}.mp4"

额外优化说明

  • 增加了对实时显示终端窗口的PID记录与关闭,避免脚本结束后残留进程;
  • 将时间码中的冒号替换为下划线,避免生成含特殊字符的文件名;
  • 增加了时间码数量奇偶性检查,提前提示错误;
  • 用ls -1确保每行一个文件名,避免文件名含空格时出错;
  • 用mapfile读取时间码到数组,比循环read更可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 07:54:17