我正在尝试使用FFmpeg将视频转换为Bash中的图像。我想使用视频的文件名来命名相应的图像(后跟一个整数)。
如果我在同一目录中导出文件,我就能做到这一点:
for file in `find . -name "*.mp4"`; do ffmpeg -i $file -q 1 $file'_'%d.jpeg; done
但是,如果我要将图像导出到所需目录,我就会出错。看起来像$ file的值不只是文件名,而是目录。
我在尝试的是什么:
for file in `find . -name "*.mp4"`; do ffmpeg -i $file -q 1 ~/testfolder/$file'_'%d.jpeg; done
我的问题是:我怎样才能正确提取文件名才能在这里使用?
答案 0 :(得分:4)
这样做,因为它适用于包含任何特殊字符的文件(包括很少使用但在文件名中有效的换行符)。
destdir=~/testfolder/
while read -u 5 -r -d '' file
do
name=$(basename "$file")
ffmpeg -i "$file" -q 1 "$destdir/${file}_%d.jpeg" </dev/null
done 5< <(find . -name "*.mp4" -print0)
basename
命令是外部程序。只使用shell扩展,您可以使用以下行获得相同的结果:
name=${file%/}
name=${name##*/}
答案 1 :(得分:2)
你既不需要基本名称也不需要循环;
您可以使用-type f
来避免find
报告其中的目录结果与-exec
选项一起直接执行您的命令。
这样的东西适用于所有mp4文件:
find . -type f -name '*.mp4' -exec bash -c 'ffmpeg -i $0 -q 1 $0'_'%d.jpeg' {} \;
参见一个小型演示测试:
$ find . -type f -name 'a*.txt' -exec bash -c 'echo ffmpeg -i $0 ' {} \;
ffmpeg -i ./a.txt
ffmpeg -i ./a spaced file.txt
ffmpeg -i ./aa.txt
ffmpeg -i ./cheatsheets/awk-cheat-sheet-gv.txt
如您所见,第二个文件在文件名中有空格,但由find
正确处理
相反,这样的间隔文件将以for loop
打破。
如果你坚持用循环来完成这项工作,那么这必须是Fred建议的while循环。
作为Fred解决方案的修改,您可以使用-printf
的{{1}}功能避免使用basename:
find
while read -r -d '' file;do
ffmpeg -i "$file" -q 1 "${file}_%d.jpeg"
done < <(find . -name "*.mp4" -printf %f\\0)
根据-printf %f
的手册页打印剥离的文件名,并在每个文件名后附加find
(null char)我们确保正确的文件名处理,即使名称包含空格或其他特殊的字符。
小测试:
\\0
答案 2 :(得分:-1)
bash命令basename
可用于此目的。
在这种情况下,以下内容应仅列出文件:
for file in $(find . -name "*.mp4"); do echo $(basename $file); done
您可以在原始代码中使用$(basename $file)
来获取文件名。
for file in $(find . -name "*.mp4"); do
ffmpeg -i "${file}" -q 1 "~/testfolder/$(basename $file)'_'%d.jpeg"
done