我想要的功能是寻找当前目录及子目录下所有与传入的分辨率相同的图片的地址。
然而,实际根本无法使用……虽然只有这么一点功能,但是架不住我要找的目录里图片多啊……差不多有 10g 了……第一版直接用不了,我调试了一下,find 还是可以接受的,但是一行一行 awk 太慢了,我尝试了多线程和回溯,勉强可以出结果了,但是我觉得不应该这么慢的,可能是我太菜了……毕竟我甚至不知道怎么把 find 的结果直接在内存中处理,甚至需要写到文件中的……
#!/usr/bin/env bash
set -euo pipefail
if [[ $# != 2 ]]; then
echo bad argument.
exit 1
fi
TEMP_FILE=".todo.find"
find . -name "*.png" >>${TEMP_FILE}
while read line; do
{
resolution=$(file "${line}" | awk -F ',' '{print $2}')
width=$(echo ${resolution} | awk '{print $1}')
[[ ${width} != $1 ]] && continue
height=$(echo ${resolution} | awk '{print $3}')
if [[ ${height} == $2 ]]; then
echo ${line}
fi
} &
done <${TEMP_FILE}
rm ${TEMP_FILE}
总之希望有大佬指点一下怎么优化这个脚本!万分感谢!!!
1
dream10201 2019-07-23 15:09:41 +08:00
用其他语言写,然后找到就别存了,直接获取信息判断
|
2
momocraft 2019-07-23 15:14:51 +08:00
10g 的图片文件一个个 file 本来就会慢
写得这么复杂,性能也未必比 `find | xargs file | grep` 好很多 |
3
0x11901 OP @dream10201 主要我也不怎么会 shell,用它是感觉这个小需求没必要用其他的语言增加复杂度……
|
5
dream10201 2019-07-23 15:28:27 +08:00
1、递归查找图片
2、获取文件信息判断分辨率 两步解决,多线程一开,走位走位 |
6
0x11901 OP @dream10201 其实我感觉可能是获取分辨率这里遇到瓶颈了,也许我能用 c 写一个小程序,输入地址打印分辨率……全部换语言太懒了不想改……
|
7
thedrwu 2019-07-23 15:38:07 +08:00 via Android
其实不是你的错。装个虚拟机,至少 10 倍速度
|
8
dream10201 2019-07-23 15:39:58 +08:00
@0x11901 不不,find 查找所有文件(耗时),写到文件里(耗时),读文件(耗时),这几个才是关键,本来可以一步搞定,非要整几步
|
9
momocraft 2019-07-23 15:51:53 +08:00
这个文件名列表多大
耗时的真的是读写这个列表(而不是每个图像文件都开 2 个 file 3 个 awk 进程)吗? |
10
ant2017 2019-07-23 15:55:54 +08:00 via Android
find . -name "*.png" |xargs file>>${TEMP_FILE}
awk -F "," -v height=$1 -v width=$2 '$1==height && $2==width' ${TEMP_FILE} |
11
0x11901 OP @dream10201 不是 find,我调了一下,find 很快的,读写也挺快的,就是 awk 太慢了。
|
14
0x11901 OP @dream10201 而且主要是我不知道怎么把这个结果搞到内存里,所以才用的 io
|
15
ETiV 2019-07-23 16:04:03 +08:00 via iPhone
xargs 有个大写 P 参数,试试这个
|
17
ReVanTis 2019-07-23 16:08:44 +08:00
awk 换成别的工具会好点吗? cut 啥的。。。应该会比 awk 快点
|
18
rrfeng 2019-07-23 16:14:26 +08:00 1
简单优化一下:
find | while read x; do file $x; done | awk ..... 总结: 1. 文件缓存没必要,增加大量 IO 2. 既然用了 awk,直接使用 awk 解决所有判断、输出的问题,不要用过多的指令(重复 fork 非常多) 3. 还是要看下到底哪一步耗时才好优化。 awk 启动慢,因为你启动了太多次,将 file 的结果合并到一起传给 awk 按行处理即可。 |
20
maxbon 2019-07-23 16:28:04 +08:00
find 可以搭配 xargs 使用,find 的结果传过来就好了,然后可以用 & 伪多线程
|
21
Rekkles 2019-07-23 16:36:04 +08:00
IO 就慢死你了
|
23
maxbon 2019-07-23 17:02:15 +08:00
find . -name "*.png" | xargs file |awk -F, '{print $1,$2}'|awk "\$(NF-2)==$1 && \$NF==$2{print\$1}"
参考一下,没测性能,应该比你的快很多吧,至少全在内存完成的 |
24
maxbon 2019-07-23 17:04:43 +08:00 1
$(NF-2)==$1
$NF==$2 这里的$1 和$2 是传过来的目标分辨率参数 |
26
xderam 2019-07-23 22:10:22 +08:00 via iPhone
windows 为啥不用 ntfs 文件系统的特性?类似于 everything 那种搜索工具就是利用 ntfs 的文件名索引 搜索速度很快
|
27
freelancher 2019-07-23 23:33:10 +08:00 via iPhone 1
我是运维。第一步 find 太吃性能了。改成 ls 加参数列出路径 grep png 出来。觉得有用点个赞。明天继续写。
|
28
iwishing 2019-07-23 23:49:35 +08:00
弄个数据库,sqlite 就行,便利一遍所有文件,把信息写入数据库。类似 everything 或者 windows search 给文件做索引。
当然如果你只跑一次就没必要了 |
29
iwishing 2019-07-23 23:50:23 +08:00
btw,建议用 python -_-b
|
30
0x11901 OP @maxbon 老哥,可用!就是感觉这一行代码已经超越了我驾驭的范围了,我还想加几个参数和指令增加点功能……就很尴尬了 😂
|
31
0x11901 OP @xderam 太菜了不会用 Windows,而且就是这门工作需要用 Windows,平时我也不打算使用 Windows
@freelancher 给你点赞了 @iwishing 一个小需求而已啊,我觉得不用这么复杂吧……而且 bash 不比 python 做这种事好太多么…… |
32
widewing 2019-07-24 00:53:23 +08:00 via Android
时间主要费在 file awk 起进程关进程上吧 同建议 python,没事别在循环里做起进程这么费时的事
|
35
Chowe 2019-07-24 10:12:15 +08:00
list=`find ./ -name "*.png" `
OLDIFS="$IFS" IFS=" " for i in $list do var=`file $i | grep "$1"` #where $1 like 1080x1920, if [ -n "$var" ] then echo $i fi done IFS="$OLDIFS" |
39
goodryb 2019-07-24 16:45:33 +08:00
建议另外搞个脚本,读取每个照片的路径和分辨率,写入到数据库中,比如 sqlite 中,脚本可以每天定时跑一下,把当天新增的文件过滤出来就行。
然后查询方面,你想怎么查就怎么查,SQL 随便写。不然你没查一次就要解析一遍文件,io 消耗太大了。 |