我有一系列目录,其中(大部分(包含视频文件,比如
test1
1.mpg
2.avi
3.mpeg
junk.sh
test2
123.avi
432.avi
432.srt
test3
asdf.mpg
qwerty.mpeg
我创建一个带有目录名称(基于其他参数(的变量(video_dir
(,并将其与find
一起使用以生成基本列表。 然后,我根据另一个变量(video_type
(过滤文件类型(因为目录中有时有非视频文件(,将其通过egrep
。 然后我打乱列表并将其保存到文件中。 该文件稍后被mplayer
用于幻灯片列表。 我目前使用以下命令来完成此操作。 我敢肯定这是一种可怕的方法,但它对我有用,即使在大目录中也非常快。
video_dir="/test1 /test2"
video_types=".mpg$|.avi$|.mpeg$"
find ${video_dir} -type f |
egrep -i "${video_types}" |
shuf > "$TEMP_OUT"
我现在想添加根据视频文件的分辨率高度过滤掉文件的功能。 我可以从中得到它。
mediainfo --Output='Video;%Height%' filename
它只返回一个数字。 我尝试使用 find 的 -exec 功能在每个文件上运行该命令。
find ${video_dir} -type f -exec mediainfo --Output='Video;%Height%' {} ;
但这只返回高度列表,而不是文件名,我不知道如何根据比较拒绝它们,例如 <480。 我可以做一个下一个循环,但这似乎是一个糟糕(缓慢(的主意。
使用来自@mark的信息,我将其修改为,
video_dir="test1"
find ${video_dir} -type f
-exec bash -c 'h=$(mediainfo --Output="Video;%Height%" "$1"); [[ $h -gt 480 ]]' _ {} ; -print
哪个有效。
您可以将egrep
替换为以下内容,以便您仍然在find
命令中(-iname
不区分大小写,-o
表示逻辑 OR(:
find test1 test2 -type f
( -iname "*.mpg" -o -iname "*.avi" -o -iname "*.mpeg" )
NEXT_BIT
然后,NEXT_BIT可以-exec bash
并以状态 0 或 1 退出,具体取决于您是要包含还是排除当前文件。所以它看起来像这样:
-exec bash -c 'H=$(mediainfo -output ... "$1"); [ $H -lt 480 ] && exit 1; exit 0' _ {} ;
因此,注意到评论中关于多余exit
陈述@tripleee建议,我得到:
find test1 test2 -type f
( -iname "*.mpg" -o -iname "*.avi" -o -iname "*.mpeg" )
-exec bash -c 'h=$(mediainfo ...options... "$1"); [ $h -lt 480 ]' _ {} ; -print
这个问答集中在一个特定的案例上,所以接受的答案并不像它可能的那样笼统。
find
如果文件列表来自find
,则可以使用其过滤工具,例如-exec
:
find ${video_dir} -type f
-exec COMMAND ;
-print
这里
- COMMAND 没有用引号括起来 -
find
读取-exec
之后的所有内容,直到一个;
find
将{}
展开到当前文件名(包括路径 - 您可能会发现-execdir
有帮助,这将cd
到文件的目录并将{}
替换为叶文件名(- COMMAND 的退出代码处理如下:
- 0 -> 真
- 非 0 -> 假
请注意,您可以构建更复杂的表达式(例如-not -exec ...
(,将"根据优先规则从左到右...... 在省略运算符的情况下假定-and
。"(每人找到(
xargs
如果文件列表来自其他地方(并且在 stdin(并且在 stdin(上可用(,则可以按如下方式使用xargs
(从 如果 xargs 是映射,什么是过滤器?)
ls | xargs -I{} bash -c "COMMAND '{}' && echo '{}'"
这是我的解决方案。
#!/bin/bash
shopt -s nullglob
video_dir=(/test1 /test2)
while IFS= read -rd '' file; do
if [[ $file = *.@(mpg|avi|mpeg|mp4) ]]; then
h=$(mediainfo --Output="Video;%Height%" "$file")
(( h >= 480 )) && echo "$file"
fi
done < <(find "${video_dir[@]}" -type f -print0)
此解决方案您可以在读取循环中处理所有内容。