我有许多按日期、摄像机频道、事件时间范围划分的视频文件 ( YYYY-MM-DD/VIDEOCHANNELNUMBER-EVENTIMERANGE.mp4
)
/2021-07-03/ch2_main_20210703074010_20210703074154.mp4
/2021-07-03/ch2_main_20210703074156_20210703074357.mp4
/2021-07-03/ch2_main_20210703074446_20210703074537.mp4
/2021-07-03/ch2_main_20210703074618_20210703075119.mp4
/2021-07-03/ch2_main_20210703075153_20210703075312.mp4
/2021-07-03/ch2_main_20210703075337_20210703080422.mp4
我想仅按日和摄像机频道合并这些剪辑(即/2021-04-03-CH1.mp4
)
我的流程是:
- 遍历每个日期文件夹 (
for VIDEODIR in */
) - 在每个文件夹中,迭代每个通道号 (
for VIDEOCHANNELNUMBER in 1 2 3 4 5 6; do
) - 对于每个频道号,找到要合并的所有视频文件 (
for f in $VIDEODIR/ch$VIDEOCHANNELNUMBER*.mp4 ; do
) - FFMPEG 合并并将该文件保存到根目录(
ffmpeg -i $VIDEOLIST -c copy "$DATE-CH$VIDEOCHANNELNUMBER.mp4"
) - 成功后删除所有原始剪辑的目录。 (
if [ $? -eq 0 ]; then rm $VIDEODIR -r fi
)
我陷入了困境,因为当由于某种原因该视频频道在当天离线而没有匹配项时,第 2 步会出错。 ( zsh: no matches found: /2021-07-03/ch1*.mp4
)。这会打破整个循环,而不是跳过并继续。
答案1
您可以使用N
glob 限定符来表示您希望 glob 扩展为空,而不是在没有匹配项时返回错误,并使用限定符/
来选择目录类型的文件。
N
在分配给数组变量时,您通常需要使用限定符:
dirs=( *(N/) )
或循环时:
for dir in *(N/)
所以,我不太清楚你想做什么,但这可能看起来像:
for dir in *(N/); do
for (( channel = 1; channel <= 6; channel++ )); do
files=( $dir/ch${channel}_*.mp4(N) )
if (( $#files )); then
ffmpeg ... $file
fi
done
done
在这里,您可以采取不同的方法来一次循环所有文件:
typeset -A list=()
for file (<1900-2100>-<1-12>-<1-31>/ch<1-6>_*.mp4(Nn))
files[$file:h-${${file:t}%%_*}.mp4]+=$file$'\0'
for output_file (${(k)list})
ffmpeg -i ${(0)list[$output_file]} -c copy $output_file &&
rm -f ${(0)list[$output_file]}
(并rmdir <1900-2100>-<1-12>-<1-31>(/^F)
随后删除空目录)。
有趣的是,这就是它的作用fish
:当没有像 in 那样的匹配时,它的 glob 会出错,zsh
除非 glob 与for
, set
(分配给变量)或 一起使用count
。