簡體   English   中英

Bash腳本執行時間過長

[英]Bash Script execution too long

我在制作一個腳本時遇到了麻煩,時間執行太長(例如24分鍾),但是時間是可變的(取決於日志的時間),並且在不久的將來,時間肯定會增加。

troube處於嵌套的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;
}

問題在於$ 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

要解決此性能問題,可以嘗試以下操作:

評估第一個findgrep命令的影響:

$ 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循環,那將花費很多:)

cat的無用用法: wc -l <file代替cat file | wc -l cat file | wc -l

wc的無用用法: while read line; do ...;done <file 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等命令可以簡化。

您正在將整個文件讀入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

循環處理效率低下

由於沒有語料或樣本輸出顯示您實際上要解析的內容,因此幾乎不可能弄清楚您實際上在做什么。 但是,您可以將此問題歸結為低效的處理和流程分叉。

使用AWK進行面向記錄的操作

日志文件通常是面向記錄的,其中每一行都是具有多個字段的記錄。 如果這是您的用例,那么AWK(或處於AWK仿真模式下的Perl / Ruby)通常是適合此工作的工具。 這樣可以確保每行僅處理一次,並且讀取行和拆分字段非常有效。

例如,使用Bash 4和GNU awk(aka 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在一個進程中處理循環和行解析,您可能會獲得很大的效率。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM