Bash遍历目录中的文件输出不存在的文件



我正在从一系列图像制作mp4文件。图像应该运行大约1小时,但我不能得到一个完整的视频,因为FFMPEG寻找一个文件,它不应该有。

[image2 @ 0x55fe14bef700] Could not open file : /mnt/run/image-005437.jpeg

令人困惑的是,我传递给ffmpeg的列表应该不包括该文件。如果我的脚本不喜欢结果,它会将文件发送到目标文件夹中名为failed

的子目录带有该编号的文件的位置

$ pwd
run/failed
]$ ls
failed-005437.jpeg 

我用来启动ffmpeg的命令如下

image_folder=$1
singularity exec --bind $work_dir:/mnt $work_dir/longleaf2.sif ffmpeg -f concat -safe 0 -y -i <(for f in /mnt/processed_images/$image_folder/image-%06d.jpeg; do echo "file '$f'";done) -vf "crop=trunc(iw/3)*2:trunc(ih/2)*2" -movflags +faststart /mnt/run/summary_files/${image_folder}.mp4

我已经检查了处理过的图像,它不存在,所以为什么ffmpeg正在寻找它?

失败运行的粘贴目录

https://pastebin.com/pF5ZefLf

我检查文件不在for循环引用的文件夹中,以便它永远不会导致错误

$ ls image-005437.*
ls: cannot access image-005437.*: No such file or directory

问题

当你运行:

for f in /mnt/processed_images/$image_folder/image-%06d.jpeg; do echo "file '$f'";done

输出:

file '/mnt/processed_images/foo/image-%06d.jpeg'

那么ffmpeg将使用序列模式类型进行图像拆分。这需要一个连续序列。

方案1:Glob

使用glob:

for f in /mnt/processed_images/$image_folder/*.jpeg; do echo "file '$f'";done

现在它将输出每个文件。在这个例子中,image-000003.jpeg不存在,所以它没有被列出:

file '/mnt/processed_images/foo/image-000001.jpeg'
file '/mnt/processed_images/foo/image-000002.jpeg'
file '/mnt/processed_images/foo/image-000004.jpeg'

解决方案2:简化并跳过concat

更好的方法是通过在ffmpeg本身中使用glob模式类型来简化您的命令,然后您可以避免concat demuxer:

image_folder=$1
singularity exec --bind "$work_dir":/mnt "$work_dir"/longleaf2.sif ffmpeg -pattern_type glob -framerate 25 -i "/mnt/processed_images/$image_folder/*.jpeg" -vf "crop=trunc(iw/3)*2:trunc(ih/2)*2,format=yuv420p" -movflags +faststart /mnt/run/summary_files/${image_folder}.mp4
  • Windows用户无法使用图像demuxer glob模式。
  • 增加了-framerate输入选项的图像分解。
  • 增加了格式过滤器,使YUV 4:2:0色度子采样兼容。
  • 变量已被引用。参见shellcheck.net。
  • FFmpeg 4.1发布分支旧。在做任何其他事情之前,请下载或编译最新版本。