0

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

麻烦在一个嵌套的for循环中:

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;
}

问题在于大于 20k 的 $totalLogsErrores ...

我可以通过其他方式做到这一点吗?

谢谢!

----------------------- 编辑 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

4 回答 4

0

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

评估您的第一个find&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 个循环,那将需要很多:)

于 2012-07-18T09:44:46.620 回答
0

cat 的无用用法: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;

最后find、grep、sed、cut等命令可以简化。

于 2012-07-18T10:13:03.257 回答
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
于 2012-07-18T10:17:20.310 回答
0

循环处理效率低下

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

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

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

例如,使用 Bash 4 和 GNU awk(又名 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 在一个进程中处理循环和行解析,您可能会获得很大的效率。

于 2012-07-18T15:10:59.977 回答