我试图获取当前目录及其子目录中所有以 .mp4 结尾的一堆文件的持续时间。我正在尝试使用 ffprobe。为了简单起见,我没有使用 find,而是使用 ls。如果它只列出以秒为单位的持续时间,那就没问题了,因为将它们全部总结起来可能超出了我的范围!
我目前的努力是这样的:
ls -a * |grep .mp4$|xargs ffprobe
由此可见
参数“SomeVideo.mp4”作为输入文件名提供,但已指定“DifferentVideo.mp4”。
我怎样才能做到这一点? ffprobe 不能一次只处理通过管道传递的一个文件吗?
答案1
和exiftool
:
$ exiftool -ext mp4 -r -n -q -p '${Duration;$_ = ConvertDuration(our $total += $_)}' . | tail -n 1
4 days 22:14:59
主要区别于@don_cristi 对一个非常相似的问题的回答,它-r -ext mp4
让 exiftool 可以递归地查找带有ext
ensions 的文件r
。
答案2
为了满足您的基本需求,您应该迭代这些文件,一次将它们传递到ffprobe
.这将允许您获取以小时、分钟、秒为单位的持续时间。
for mp4 in *.mp4
do
echo "Processing $mp4"
ffprobe "$mp4" 2>&1 | awk '/Duration/ {print $2}'
done
稍微环顾四周更仔细地,可以ffprobe
直接传递秒数
for mp4 in *.mp4
do
echo "Processing $mp4"
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$mp4"
done
完成此操作后,将它们全部加在一起并不是一个巨大的飞跃
for mp4 in *.mp4
do
echo "Processing $mp4"
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$mp4"
done |
awk -F '
{ sec += $1 } # Total time (seconds)
END {
h = int(sec / 3600); # Hours
m = int((sec - (h*3600)) / 60); # Minutes
s = sec - (h*3600) - (m*60); # Seconds
printf "%d (%d hour, %d min, %d sec)\n", sec, h, m, s # Print the result
}
'
最后,为了不仅处理当前目录下的文件,还处理所有子目录下的文件,请修改外层循环。下一步使用允许匹配子目录的bash
功能**
shopt -s globstar # Enable extended globbing
for mp4 in **/*.mp4
do
echo "Processing $mp4"
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$mp4"
done |
# Continue as before...
答案3
xargs
将在命令中添加尽可能多的输入参数 - 它不知道单个文件的限制ffprobe
如果您想ffprobe
每个输入运行一次,请使用
... | xargs -l ffprobe
或者
... | xargs -L 1 ffprobe
为了理解,只需比较这两个命令的输出
seq 1 3 | xargs echo
seq 1 3 | xargs -l echo
请注意,ls
出于多种原因,不鼓励使用 -output 作为输入。
更好地使用find
- 尽管你努力简化 - 最好使用 -NULL
分隔符来避免特殊字符的问题:
find -maxdepth 1 -name '*mp4' -print0 | xargs -0 ffprobe
ffprobe
下一个问题是- get Seconds only 就像 did 的输出这里。然后你可以使用例如来总结它awk
。