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

解决zsh嵌套for循环处理视频合并时的‘no matches found’错误

解决zsh中无匹配文件时循环中断的问题,同时优化FFmpeg合并逻辑

你遇到的核心问题是zsh的默认行为导致的:当通配符(比如ch1*.mp4)没有匹配到任何文件时,zsh会直接抛出no matches found错误并中断整个循环,而不是像bash那样跳过无匹配的情况。另外,你的FFmpeg合并命令也有小瑕疵——直接用-i $VIDEOLIST会把多个文件作为独立输入流,最终输出的视频可能包含多轨而非连续的单轨视频,这里也一起帮你修正。

下面是修正后的完整脚本,附带详细解释:

# 开启nullglob选项:当通配符无匹配时,展开为空字符串而非报错
setopt nullglob

# 遍历所有日期文件夹(*/会匹配所有子目录,nullglob确保无目录时不执行循环)
for VIDEODIR in */; do
    # 提取日期:去掉目录末尾的斜杠,比如把"2021-07-03/"变成"2021-07-03"
    DATE="${VIDEODIR%/}"
    
    # 遍历每个摄像头通道
    for VIDEOCHANNELNUMBER in 1 2 3 4 5 6; do
        # 收集当前日期+通道的所有视频文件,按文件名排序(确保时间顺序正确)
        VIDEO_FILES=("$VIDEODIR/ch${VIDEOCHANNELNUMBER}"*.mp4)
        
        # 如果没有找到任何文件,跳过当前通道
        if [[ ${#VIDEO_FILES[@]} -eq 0 ]]; then
            echo "No files found for channel $VIDEOCHANNELNUMBER on $DATE, skipping..."
            continue
        fi
        
        # 生成FFmpeg需要的文件列表(每个文件路径前加file:)
        LIST_FILE="/tmp/concat_${DATE}_ch${VIDEOCHANNELNUMBER}.txt"
        > "$LIST_FILE"  # 清空或创建文件
        for f in "${VIDEO_FILES[@]}"; do
            echo "file '$PWD/$f'" >> "$LIST_FILE"
        done
        
        # 使用FFmpeg的concat demuxer合并视频(同编码下-c copy保证无损快速合并)
        OUTPUT_FILE="${DATE}-CH${VIDEOCHANNELNUMBER}.mp4"
        ffmpeg -f concat -safe 0 -i "$LIST_FILE" -c copy "$OUTPUT_FILE"
        
        # 检查合并是否成功,成功则删除原目录
        if [[ $? -eq 0 ]]; then
            echo "Successfully merged $OUTPUT_FILE, deleting source directory $VIDEODIR..."
            rm -r "$VIDEODIR"
            rm "$LIST_FILE"  # 清理临时文件
        else
            echo "Failed to merge $OUTPUT_FILE, keeping source files."
            rm "$LIST_FILE"
        fi
    done
done

关键修正点说明:

  1. setopt nullglob:这是解决你核心问题的关键——开启后,当通配符没有匹配到任何文件时,会展开成空字符串,而不是抛出错误中断循环。
  2. 数组存储视频文件:用VIDEO_FILES=("$VIDEODIR/ch${VIDEOCHANNELNUMBER}"*.mp4)把匹配到的文件存入数组,方便后续判断是否有文件,且数组默认按文件名排序(你的文件名包含时间戳,刚好符合合并顺序要求)。
  3. FFmpeg concat demuxer:相比直接用多个-i参数,这种方式更可靠,能确保视频按顺序合并成连续的单轨视频,-safe 0允许使用绝对路径,避免FFmpeg报错。
  4. 跳过空通道:通过${#VIDEO_FILES[@]} -eq 0判断是否有文件,没有则直接continue跳过当前通道,继续处理下一个。

其他可选方案(不用nullglob):

如果你不想修改zsh的全局选项,也可以用find命令来查找文件,完全避免通配符匹配问题:

for VIDEODIR in */; do
    DATE="${VIDEODIR%/}"
    for VIDEOCHANNELNUMBER in 1 2 3 4 5 6; do
        # 用find查找并按文件名排序
        VIDEO_FILES=($(find "$VIDEODIR" -maxdepth 1 -name "ch${VIDEOCHANNELNUMBER}*.mp4" -type f | sort))
        if [[ ${#VIDEO_FILES[@]} -eq 0 ]]; then
            echo "No files found for channel $VIDEOCHANNELNUMBER on $DATE, skipping..."
            continue
        fi
        # 后续合并逻辑和上面的脚本一致
    done
done

内容的提问来源于stack exchange,提问作者Mr. Demetrius Michael

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 10:45:28