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两行的逻辑依赖截图数量为偶数,且未处理行读取失败的情况。
修复方案
核心改进点
- 可靠提取时间码:利用MPV截图文件名的格式(
[文件名]-(时间码)-[序号].jpg),用正则匹配提取括号内的时间码,避免固定字符位置的误差; - 安全处理成对时间码:先将所有时间码存入数组,再遍历数组两两分组处理,确保入点和出点正确配对。
修复后的脚本
#!/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
相关产品推荐
相关产品推荐

