如何优化bash脚本? (查找文件,忽略白名单上的文件,报告休息)

时间:2010-11-04 10:14:55

标签: arrays performance bash

我编写了这个脚本来查找$ WWWUSER具有写权限的所有文件/目录。首先,我将剩余的匹配项存储在临时文件中。我新的必须有一种不使用文件的方式,所以这是我的“解决方案”。它有效,但速度很慢。有什么提示吗?

更新 在包含大约7k目录和30k文件(~8k白名单)的目录结构上,脚本大约需要15分钟...(ext3文件系统,UW320 SCSI硬盘)。

#!/usr/bin/env bash
# Checks the webroot for files owned by www daemon and
# writable at the same time. This is only needed by some files
# So we'll check with a whitelist

WWWROOT=/var/www
WWWUSER=www-data
WHITELIST=(/wp-content/uploads
/wp-content/cache
/sitemap.xml
)
OLDIFS=$IFS
IFS=$'\n'

LIST=($(find $WWWROOT -perm /u+w -user $WWWUSER -o -perm /g+w -group $WWWUSER))
IFS=$OLDIFS

arraycount=-1
whitelist_matches=0

for matchedentry in "${LIST[@]}"; do
        arraycount=$(($arraycount+1))

        for whitelistedentry in "${WHITELIST[@]}"; do
                if [ $(echo $matchedentry | grep -c "$whitelistedentry") -gt 0 ]; then
                        unset LIST[$arraycount]
                        whitelist_matches=$(($whitelist_matches+1))
                fi
        done
LISTCOUNT=${#LIST[@]}
done

if [ $(echo $LISTCOUNT) -gt 0 ]; then
        for item in "${LIST[@]}"; do
                echo -e "$item\r"
        done
        echo "$LISTCOUNT items are writable by '$WWWUSER' ($whitelist_matches whitelisted)."
else
        echo "No writable items found ($whitelist_matches whitelisted)."
fi

2 个答案:

答案 0 :(得分:1)

还有另一种可能性。将白名单更改为正则表达式模式,您可以使用= ~bash正则表达式运算符(版本3及更高版本)快速匹配列表中任何找到的单词:     如果($字=〜$图案) $ pattern可能是     “^(whitelistentry1 | whitelistentry2 | whitelistentry3 | ...)$”

答案 1 :(得分:1)

(我没有设置方便对它进行测试,但应该工作......)

#!/usr/bin/env bash
# Checks the webroot for files owned by www daemon and
# writable at the same time. This is only needed by some files
# So we'll check with a whitelist

WWWROOT=/var/www
WWWUSER=www-data
WHITELIST="(/wp-content/uploads|/wp-content/cache|/sitemap.xml)"

listcount=0
whitelist_matches=0

while IFS="" read -r matchedentry; do
    if [[ "$matchedentry" =~ $WHITELIST ]]; then
        ((whitelist_matches++))
    else
        echo -e "$matchedentry\r"
        ((listcount++))
    fi
done < <(find "$WWWROOT" -perm /u+w -user $WWWUSER -o -perm /g+w -group $WWWUSER)

if (( $listcount > 0 )); then
        echo "$listcount items are writable by '$WWWUSER' ($whitelist_matches whitelisted)."
else
        echo "No writable items found ($whitelist_matches whitelisted)."
fi
编辑:我已经将丹尼斯威廉姆森的数学建议纳入其中;另外,这是一种从数组开始构建WHITELIST模式的方法:

WHITELIST_ARRAY=(/wp-content/uploads
/wp-content/cache
/sitemap.xml
)

WHITELIST=""
for entry in "${WHITELIST_ARRAY[@]}"; do
    WHITELIST+="|$entry"
done
WHITELIST="(${WHITELIST#|})"  # this removes the stray "|" from the front, and adds parens

Edit2:Sorpigal关于消除新进程的评论让我思考 - 我怀疑这个版本的大部分加速都来自于每个扫描文件没有运行〜grep的〜{40}调用,而只是稍微移除了数组操作,但我想到如果你不需要最后的总数,你可以删除主while循环并用它替换它:

find "$WWWROOT" -perm /u+w -user $WWWUSER -o -perm /g+w -group $WWWUSER | grep -v "$WHITELIST"

...它运行grep,但只运行一次(并通过该单个实例运行整个文件列表),一旦启动grep将能够扫描文件列表比bash循环快......