Bash脚本执行时间太长

时间:2012-07-18 07:55:15

标签: bash shell loops for-loop

我遇到了一个我做过的脚本有问题,时间执行太长(比如24分钟),但时间是可变的(取决于日志),并且在不久的将来时间肯定会增加

这个问题正在进行中:

obtener_ErroresLanzados()
{
        #Buscamos los equipos del log lanzados_a_pendientes en los logs de instala_sw_qcc para ver el porque no se han lanzado.
        totalLanzadosPendientes=`cat $rutaTemporales/lanzados_a_pendientes.log | wc -l`;
        lanzadosPendientes=$(cat $rutaTemporales/lanzados_a_pendientes.log);
        #grep "$paqueteBuscado" instala_sw_qcc_2012*.log | cut -f 1 -d ":" > $rutaTemporales/logsErrores.log;
        find $rutaTrazas -name "instala_sw_qcc_2012*" | xargs grep -l "$rutaQcc/$paqueteBuscado" | xargs grep -l "ERROR \[" | cut -f 9 -d "/" > $rutaTemporales/logsErrores.log;
        logsErrores=$(cat $rutaTemporales/logsErrores.log);
        totalLogsErrores=`cat $rutaTemporales/logsErrores.log | wc -l`;

for (( j=1; j<=$totalLanzadosPendientes; j++ ))
    do
equipoBusqueda=`echo $lanzadosPendientes | cut -f $j -d " "`;
            for (( k=1; k<=$totalLogsErrores; k++ ))
            do
            logBusqueda=`echo $logsErrores | cut -f $k -d " "`;
            grep "ERROR \[$equipoBusqueda\]" $rutaTrazas/$logBusqueda >> $rutaTemporales/erroresPendientes.log;
            if [ $? -eq 0 ];then
                    break;
            fi;
                    done;
    done;
    cat $rutaTemporales/erroresPendientes.log | sed 's/  / /g' | sed '/No se ha podido/d' | cut -f 7-14 -d " " | sort -u > $rutaTemporales/erroresPendientes_Final.log;
}

问题是$ totalLogsErrores大于20k ......

我可以通过其他方式这样做吗?

谢谢!

-----------------------编辑1 ---------------------- -

$ time find $rutaTrazas -name "instala_sw_qcc_2012*" | xargs grep -l "$rutaQcc/$paqueteBuscado" | xargs grep -l "ERROR [" | cut -f 9 -d "/" 

real 0m3.862s
user 0m0.959s
sys 0m2.941s 

$ du -h ../trazas/instala_sw_qcc_20120718091838.log 

4.0K ../trazas/instala_sw_qcc_20120718091838.log 

$ time grep error ../trazas/instala_sw_qcc_20120718091838.log 

real 0m0.001s
user 0m0.001s
sys 0m0.000s

4 个答案:

答案 0 :(得分:0)

要确定此性能问题,您可以尝试以下操作:

评估您的第一个find&amp; grep命令:

$ time find $rutaTrazas -name "instala_sw_qcc_2012*" | xargs grep -l "$rutaQcc/$paqueteBuscado" | xargs grep -l "ERROR \[" | cut -f 9 -d "/" > $rutaTemporales/logsErrores.log;

在嵌套的for循环中,评估grep的影响。文件有多大?在您的评论中,您提到了100*10000重复,如果每个grep花费4毫秒,这将是巨大的。

当您拥有大量子目录时,find会变得昂贵,而当您的文件足够大时,grep会变得昂贵。

$ du -h file.out 
  20K   file.out


$ time grep ERROR file.out 

real    0m0.004s
user    0m0.000s
sys     0m0.003s

如果你有1000000个循环,那将需要很多:)

答案 1 :(得分:0)

无用的猫:wc -l <file而不是cat file | wc -l

无用的使用wc:while read line; do ...;done <file而不是for循环:

find $rutaTrazas -name "instala_sw_qcc_2012*" | xargs grep -l "$rutaQcc/$paqueteBuscado" | xargs grep -l "ERROR \[" | cut -f 9 -d "/" > $rutaTemporales/logsErrores.log;
while read equipoBusqueda; do
    while read logBusqueda; do
        grep "ERROR \[$equipoBusqueda\]" $rutaTrazas/$logBusqueda >> $rutaTemporales/erroresPendientes.log
        if [ $? -eq 0 ];then
            break; 
        fi;
    done <$rutaTemporales/logsErrores.log
done <$rutaTemporales/lanzados_a_pendientes.log
cat $rutaTemporales/erroresPendientes.log | sed 's/  / /g' | sed '/No se ha podido/d' |
    cut -f 7-14 -d " " | sort -u > $rutaTemporales/erroresPendientes_Final.log;

最终查找,grep,sed,cut等命令可能会被简化。

答案 2 :(得分:0)

Yo正在将整个文件读入一个shell变量,然后使用一个提取每一行 单独的切割过程。这是非常低效的。

很难破译你想要做什么。也许你可以替换这个功能 用这样的东西:

$ cd $rutaTrazas
$ sed 's/^/ERROR \[/; s/$/\]/' $rutaTemporales/lanzados_a_pendientes.log > search_strings
$ xargs grep -F -f search_strings \
    < $rutaTemporales/logsErrores.log \
    >> $rutaTemporales/erroresPendientes.log
$ < $rutaTemporales/erroresPendientes.log \
    sed 's/  / /g' | sed '/No se ha podido/d' |
    cut -f 7-14 -d " " | 
    sort -u > $rutaTemporales/erroresPendientes_Final.log

答案 3 :(得分:0)

使用循环进行低效处理

几乎不可能弄清楚你真正想要在这里做什么,因为没有语料库或示例输出显示你实际想要解析的内容。但是,您可以将此问题归结为低效处理和处理分叉。

使用AWK进行面向记录的操作

日志文件通常是面向记录的,其中每一行都是具有多个字段的记录。如果这是您的用例,则AWK(或AWK仿真模式下的Perl / Ruby)通常是该工作的正确工具。这确保您只处理每一行,并且读取行和拆分字段非常有效。

例如,使用Bash 4和GNU awk(a.k.a. gawk):

shopt -s globstar
awk 'BEGIN {error_count = 0}
     /ERROR/ {print $9; ++error_count}
     # other pattern/action pairs
     END {print "Total errors:", error_count}
    ' **/instala_sw_qcc_2012* > /path/to/output/file

如果您确实需要,可以将多个模式匹配应用于每一行,或者直接输出到awk内部的单个文件。但是,通过让awk在一个进程中处理循环和行解析,您可能会获得很高的效率。