一个 bash 脚本性能优化的问题?

2019-07-23 15:03:16 +08:00
 0x11901

我想要的功能是寻找当前目录及子目录下所有与传入的分辨率相同的图片的地址。

环境

  1. Windows
  2. Git Bash + MinGW

思路

  1. 用 find 找到所有后缀名为 png 的文件的相对路径
  2. 把结果写到一个 temp 文件里
  3. 用 read 读取 temp 文件每一行,以一行一行处理相对路径
  4. 使用 file 获得对应路径的图片文件的信息
  5. 使用 awk 得到其中的分辨率字段
  6. 如果分辨率正确,打印相对路径

问题

然而,实际根本无法使用……虽然只有这么一点功能,但是架不住我要找的目录里图片多啊……差不多有 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}

需求

总之希望有大佬指点一下怎么优化这个脚本!万分感谢!!!

2707 次点击
所在节点    问与答
39 条回复
Rekkles
2019-07-23 16:36:04 +08:00
IO 就慢死你了
0x11901
2019-07-23 17:01:08 +08:00
@maxbon 加完班晚上回去改改试试!

@Rekkles 然后貌似不是 IO 的问题
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}"
参考一下,没测性能,应该比你的快很多吧,至少全在内存完成的
maxbon
2019-07-23 17:04:43 +08:00
$(NF-2)==$1
$NF==$2
这里的$1 和$2 是传过来的目标分辨率参数
maxbon
2019-07-23 17:12:18 +08:00
@0x11901 #22 刚跑了 10 万图片,要 10s,慢在 find
xderam
2019-07-23 22:10:22 +08:00
windows 为啥不用 ntfs 文件系统的特性?类似于 everything 那种搜索工具就是利用 ntfs 的文件名索引 搜索速度很快
freelancher
2019-07-23 23:33:10 +08:00
我是运维。第一步 find 太吃性能了。改成 ls 加参数列出路径 grep png 出来。觉得有用点个赞。明天继续写。
iwishing
2019-07-23 23:49:35 +08:00
弄个数据库,sqlite 就行,便利一遍所有文件,把信息写入数据库。类似 everything 或者 windows search 给文件做索引。
当然如果你只跑一次就没必要了
iwishing
2019-07-23 23:50:23 +08:00
btw,建议用 python -_-b
0x11901
2019-07-24 00:30:35 +08:00
@maxbon 老哥,可用!就是感觉这一行代码已经超越了我驾驭的范围了,我还想加几个参数和指令增加点功能……就很尴尬了 😂
0x11901
2019-07-24 00:33:12 +08:00
@xderam 太菜了不会用 Windows,而且就是这门工作需要用 Windows,平时我也不打算使用 Windows

@freelancher 给你点赞了

@iwishing 一个小需求而已啊,我觉得不用这么复杂吧……而且 bash 不比 python 做这种事好太多么……
widewing
2019-07-24 00:53:23 +08:00
时间主要费在 file awk 起进程关进程上吧 同建议 python,没事别在循环里做起进程这么费时的事
ReVanTis
2019-07-24 09:18:05 +08:00
@xderam
想用 ntfs 特性,find 可以换成 everything 的命令行版,es
maxbon
2019-07-24 09:38:36 +08:00
@0x11901 #30 你要做成一个常用脚本的话,建议拆开写成 function
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"
0x11901
2019-07-24 11:29:06 +08:00
@maxbon 比如说我想加一个-f 参数实现模糊查找,让分辨率的范围+-5,我该怎么拆开这行命令啊?
xderam
2019-07-24 14:48:58 +08:00
@0x11901 用对方法 效率会有一个量级的提升的
maxbon
2019-07-24 15:07:00 +08:00
@0x11901 #36 你可以把这个判断做成范围的,但是会牺牲性能 $(NF-2)==$1 && $NF==$2
goodryb
2019-07-24 16:45:33 +08:00
建议另外搞个脚本,读取每个照片的路径和分辨率,写入到数据库中,比如 sqlite 中,脚本可以每天定时跑一下,把当天新增的文件过滤出来就行。

然后查询方面,你想怎么查就怎么查,SQL 随便写。不然你没查一次就要解析一遍文件,io 消耗太大了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://tanronggui.xyz/t/585451

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX