【问题标题】:Performance Issue - Looping through many xml files性能问题 - 循环通过许多 xml 文件
【发布时间】:2014-02-05 15:02:18
【问题描述】:

我有一份价值长达数年的每日 xml 报告,我正在尝试查看每一份报告并找到购买日期,并确定它是否比文件日期至少早一年。如果是这样,我将文件名和购买日期写入日志。问题是性能真的很差。

#!/bin/bash

for file in *xml ; do
fileDate=`echo ${file} | cut -c 18-35 | sed 's/.xml//'`
fileDateSeconds=`date --date="${fileDate}" +"%s"`
awk '/PurchaseDate/ {print}' ${file} >> /tmp/yamExport/tempFile.txt
cat /tmp/yamExport/tempFile.txt | while read input
do
        lineDate=`echo ${input} | cut -c 15-24`
        lineDateSeconds=`date --date="${lineDate}" +"%s"`
        delta=`expr $fileDateSeconds - $lineDateSeconds`
        if [ "$delta" -gt "31556926" ]
        then
        #echo "$file : $input"
        echo "$file : $input" >> /tmp/yamExport/yamExportTimestamps2.log
        fi
done
done

一开始我只是逐行遍历整个文件

cat ${file} | while read input
do
        if [[ "$input" =~ "PurchaseDate" ]]
        then

但后来我确定使用 awk 快速抓取所有带有 PurchaseDate 的行并输出到临时文件然后循环遍历会更快(但仍然很慢)。如果有人对我如何提高性能有任何建议,那将非常有帮助。我可以像循环一样对 awk 语句的输出进行操作吗?如果我能做到这一点,我认为性能会好得多。

感谢任何提示。

【问题讨论】:

    标签: xml performance bash loops awk


    【解决方案1】:

    将 awk 输出写入临时文件肯定会影响您的性能。此外,您正在 追加 到该临时文件,因此您正在为 每个 后续 xml 文件处理第一个 xml 文件的结果。

    此代码最大限度地减少了您需要调用的外部进程的数量

    for file in *xml ; do
        fileDateSeconds=$(date --date="${file:17:18}" +"%s")
        grep -F 'PurchaseDate' "$file" |
        while read input; do
            lineDateSeconds=$(date --date="${input:14:10}" +"%s")
            if (( (fileDateSeconds - lineDateSeconds) > 31556926 )); then
                echo "$file : $input"
            fi
        done
    done > /tmp/yamExport/yamExportTimestamps2.log
    

    我将awk 更改为grep,这是在文件中查找行的更合适的工具。

    将重定向移到外循环之外的输出文件应该会减少必须打开文件的次数。

    【讨论】:

    • 快! :-) :-) :-) :-) :-)
    • 首先,感谢您的建议。我不敢相信我忽略了附加到临时文件,这对我来说真的很糟糕。您能否向我解释以下内容以供我理解:$(date --date="${file:17:18}"?文件名的格式为 12345_export_2013-4-4.xml 所以看来这段代码没有最后考虑“.xml”,我最终得到一个“无效”的日期格式。
    • 与此同时,我使用了您的建议,只保留了我设置 fileDate 和 fileDateSeconds 的 2 行。您的代码提高的速度非常重要。谢谢!如果您有时间,如果您能详细说明我的其他问题,我会很感兴趣。谢谢。
    • ${var:a:b} 形式是 $var 的子字符串,从第 a 个字符开始,长度为 b。请出示真实文件名:12345_export_2013-4-4.xml 不满足echo ${file} | cut -c 18-35 | sed 's/.xml//'
    • 假设文件格式是“stuff_stuff_date.xml”,我会这样做:fileDate=${file##*_}; fileDate=${fileDate%.xml}——首先去掉最右边的下划线,然后去掉扩展名。
    【解决方案2】:

    这里有一些想法:

    #!/bin/bash
    
    for file in *xml ; do
    fileDate=`echo ${file} | cut -c 18-35 | sed 's/.xml//'`
    fileDateSeconds=`date --date="${fileDate}" +"%s"`
    grep PurchaseDate ${file} | while read input
    do
        lineDate=`echo ${input} | cut -c 15-24`
        lineDateSeconds=`date --date="${lineDate}" +"%s"`
        delta=$((fileDateSeconds - lineDateSeconds))
        if [ "$delta" -gt "31556926" ]
        then
        echo "$file : $input"
        fi
    done
    done > /tmp/yamExport/yamExportTimestamps2.log
    

    【讨论】:

    • 一些解释性文字将有助于突出您的更改。
    • 我正要添加它作为一个编辑,当我看到你已经做得这么好,所以我没有打扰,只是赞成你的答案!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-21
    • 1970-01-01
    • 2020-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多