我想将所有具有一定时长的视频文件移动到某个目录。在这个答案我找到了一种探测视频文件时长的方法:
ffprobe-i一些视频-show_entries 格式=持续时间-v 安静-of csv="p=0"
我想用它做这样的事:
find . -test <test for duration> -exec mv {} /path/to/target ';'
但是,似乎find
不支持测试的任意脚本(没有-test
开关)。我错过了什么吗?这根本就不可能吗find
?我最好只写一个python脚本吗?
答案1
你可以使用-exec
。-test
编写一个脚本,接受一个文件名参数,如果文件符合条件则退出 0,否则退出非零。我的系统上没有 FF 软件(例如 ffprobe
),所以我无法检查这一点,但类似
#!/bin/sh
if dur=$(ffprobe -i "$1" -show_entries format=duration -v quiet -of csv="p=0")
then
[ "$dur" -ge 900 ]
exit
else
exit
fi
将检查视频的持续时间是否大于等于 15 分钟,假设ffprobe
输出为整数秒数。(如果它报告 mm:ss 或 ss.ddd,我将一些琐碎的修改留给您,但请参见下面的示例以获得启发。)解释:if
如果失败,则ffprobe
失败;在这种情况下,我们将下降到较低的位置exit
并以错误状态从 退出ffprobe
。如果ffprobe
成功,我们测试其输出("$dur"
),然后使用该测试的结果退出。这也可以写成
[ "$dur" -ge 900 ] && exit 0 || exit 1
事实上,全部的脚本实际上可以简化为
dur=$(ffprobe -i "$1" -show_entries format=duration -v quiet -of csv="p=0") \
&& [ "$dur" -ge 900 ]
因此,将脚本命名为check_dur
:
find . -exec ./check_dur {} ';'-exec mv {} /path/to/target ';'
这是有效的,因为正如我所说,-exec
它起到测试的作用,-exec
只有第一次-exec
成功(以状态 0 退出)后的事情才会被处理。
正如我所说的,我的系统上没有 FF 软件(例如ffprobe
),因此我使用这个脚本进行了测试:
#!/bin/sh
if mod=$(stat -c%y "$1")
then
mod=${mod#*-}
mod=${mod%%-*}
mod=${mod#0}
[ $(( mod%2 )) = 0 ]
exit
else
exit
fi
测试文件或目录的修改日期是否在双数月。注意:在我的 (en_US) 系统上, 以 格式输出修改日期。因此,上述代码stat -c%y filename
yyyy-mm-dd HH:MM:SS.ddddddddd -(TZ)
- 去掉年份(从左边开始),
- 去掉月份后面的所有内容,然后
- 去掉前导的
0
(如果有)(因为$((…))
将前导零解释为数字是八进制的指示,因此它会报告08
和 的错误09
)。
其他几点说明:
对于
mv
,可以通过将命令更改为来稍微改进一下find . -exec ./check_dur {} ';' -exec mv -t /path/to/target {} +
它将mv
对许多文件执行一次。您不能对第一个执行此操作-exec
,因为-exec ... +
不能用作测试。2. 如果您不想编写单独的脚本,则可以使用sh -c
并内联脚本;例如,
find . -exec sh -c 'dur=$(ffprobe -i "$1" -show_entries format=duration -v quiet -of csv="p=0") && [ "$dur" -ge 900 ]' sh {} ';'-exec mv -t /path/to/target {} +
这将创建一个单行小脚本( 后面的字符串sh -c
),并将文件名 ( {}
) 作为参数传递给它。 的某些版本find
允许您将 合并{}
到小脚本中,但这不是一个好主意:
- 它不适用于所有版本的
find
,并且 - 即使它有效,一般来说,对于某些文件名它也会失败(甚至可能灾难性地失败)。