CPU过载:需要删除(sed -n)

时间:2016-09-19 11:06:13

标签: bash sed

CPU过载。如果我运行它,我需要找到一种运行脚本的方法,而不使用(sed -n)它可以获得很大的CPU功率。

#!/bin/bash
 # this script should read the log that i enter and find the last five min
 # give me a count and if i need to i can enter up to 5 different key
 # words to search for.
loyg=$1
loug=$(echo "$1" | sed -e 's/\//\n/g'  | tail -n1)
var0=$2
var=$3
var1=$4
var2=$5
dates=$(date +%s)
date=$(date +"%d.%m.%Y %H:%M")
datepoint=$(date +"%d.%m.%Y %H:%M" -d "5 mins ago")
    sleep 2
if [ -f $loug ];then
      intex=$(sed -n "/$date/,/$datepoint/p" "$loyg")
      count=$(echo  "$intex" | wc -l)
      error=`echo "$intex" | grep "$var0"`
      anyn=`echo "$intex" | grep "$var"`
      fails=$(echo  "$error" | wc -l)
      rand=$(echo  "$anyn" | wc -l)
      anyn1=`echo "$intex" | grep "$var1"`
      rand1=$(echo  "$anyn1" | wc -l)
      anyn2=`echo "$intex" | grep "$var2"`
      rand2=$(echo  "$anyn2" | wc -l)
fi
if   [ "$var0" != "" ] ;then
    echo "$dates: $count" "$fails" "$rand" "$rand1" "$rand2"    

    >> "stat_$loug-"$(date +"%Y%m%d")
    elif [ "$var" != "" ] ;then
    echo "$dates: $count" "$fails" "$rand" "$rand1" "$rand2" 
    >> "stat_$loug-"$(date +"%Y%m%d")
    elif [ "$var1" != "" ] ;then
    echo "$dates: $count" "$fails" "$rand" "$rand1" "$rand2"    
    >> "stat_$loug-"$(date +"%Y%m%d")
    elif [ "$var2" != "" ] ;then
    echo "$dates: $count" "$fails" "$rand" "$rand1" "$rand2"   
    >> "stat_$loug-"$(date +"%Y%m%d")
    else
    echo "$dates: $count" "0" "0" "0" "0" >> "stat_$loug-"$(date +"%Y%m%d")
fi
    scp "stat_$loug-"$(date +"%Y%m%d") datacopy2@vimapmop-    
    sta01.it.bwns.ch:/var/log/statistic/sis/"stat_$loug-"$(date +"%Y%m%d")  
    echo done

我需要用sed -n替换它的行,它使用了很多CPU的功率

我尝试用“awk”运行它,但它没有用,也许我跑错了但是它不认为这就是我做的:

intex=$(awk '{ print "/$date/,/$datepoint/p"}' "$loyg")

1 个答案:

答案 0 :(得分:0)

我严重怀疑主要问题是sed命令本身 为了测试这个理论,只需要时间:

$ loyg="some_reasonable_value"
$ date=$(date +"%d.%m.%Y %H:%M")
$ datepoint=$(date +"%d.%m.%Y %H:%M" -d "5 mins ago")
$ time { sed -n "/$date/,/$datepoint/p" "$loyg"; } > /dev/null

您的脚本最大的问题是它受pipe-itis的影响 例如,$loug的分配:

loug=$(echo "$1" | sed -e 's/\//\n/g'  | tail -n1)

回应" $ 1"的价值到sed(外部实用程序)将每个/更改为new line,然后将其传输到tail(也是外部实用程序)以选择最后一行。 /> 整个管道的作用是选择/之后的最后一个值 这可以简单地完成:

loug=${1##*/}

即删除变量$1前面的所有内容,直到最后/。没有外部实用程序,更快,更简单。

可以说这不是一个大问题,因为它只被调用一次,整个脚本只需要额外的执行时间。

是的,但是对于大文件的整个内容重复这样的构造将花费很长时间。每一行都会增加一些延迟,直到它变得很慢。

事实上,在第一个if块内的第一行所做的是:

intex=$(sed -n "/$date/,/$datepoint/p" "$loyg")

这会将行列表复制到变量$intex 然后,重复过滤该行列表并将其复制到其他变量:

error=`echo "$intex" | grep "$var0"`

所有最终只计算行数:

fails=$(echo  "$error" | wc -l)

这两行可以通过制作grep来打印计数来完成 这两行都将缩减为:

fails=`echo "$intex" | grep -c "$var0"`

这将避免使用内存来存储$error以及shell脚本处理大量行所需的时间过长。

但是:我们可以做得更好吗?

当然!!: 一旦我们意识到脚本的那一部分需要的是五个计数(五个数字):

$count $fails $rand $rand1 $rand2

我们可以构建一个AWK脚本(一个比shell脚本更好的处理大文件的工具)来生成五个计数:

    getcounts(){
        awk -v dp="$datepoint" -v d1="$date" -v v0="$var0" -v va="$var" -v v1="$var1" -v v2="$var2" '
            ($0~dp),($0~d1){
                                                  count++;
                             if (v0!="" && $0~v0) fails++;
                             if (va!="" && $0~va) rand0++ ;
                             if (v1!="" && $0~v1) rand1++;
                             if (v2!="" && $0~v2) rand2++;
                           }
                       END { 
                             printf( "%d %d %d %d %d",count,fails,rand0,rand1,rand2 );
                           }
        ' "$loyg"
    }

awk脚本只在内存中保留五个数字(内存消耗非常低),处理日志中的所有行比shell快得多。

您的脚本的其他一些问题:

  1. 包含所有测试的第二个if语句和文件的>>
    可以简化为这四行:

    outlog="stat_$loug-"$(date +"%Y%m%d")
    result="$dates: $count $fails $rand $rand1 $rand2"
    [[ $var0 || $var || $var1 || $var2 ]] || result="$dates: $count 0 0 0 0"
    echo "$result" >> "$outlog"
    

    如果在awk脚本中完成每个var0 / var ...等的测试,则可以完全删除。

  2. / $ date /,/ $ datepoint /的顺序对我来说似乎不对。 $datepoint是第一个及时的,因此应该在$date之前。

    awk脚本包含了此更改。

  3. 最终脚本

    #!/bin/bash
    
    read loyg var0 var var1 var2 <<<"$@"
    
    loug=${loyg##*/}
    
    outlog="stat_$loug-"$(date +"%Y%m%d")
    
    datepoint=$(date +"%d.%m.%Y %H:%M" -d "5 mins ago")    
    dates=$(date +%s)
    date=$(date +"%d.%m.%Y %H:%M")
    
        getcounts(){
            awk -v dp="$datepoint" -v d1="$date" -v v0="$var0" -v va="$var" -v v1="$var1" -v v2="$var2" '
                ($0~dp),($0~d1){
                                                      count++;
                                 if (v0!="" && $0~v0) fails++;
                                 if (va!="" && $0~va) rand0++;
                                 if (v1!="" && $0~v1) rand1++;
                                 if (v2!="" && $0~v2) rand2++;
                               }
                           END { 
                                 printf( "%d %d %d %d %d",count,fails,rand0,rand1,rand2 );
                               }
            ' "$loyg"
        }
    
    
    if [ -f "$loug" ]; then
            result="$( getcounts )"
    else
            result="0 0 0 0 0"
    fi
    
    echo "$dates: $result" >> "$outlog"
    
    destfile="datacopy2@vimapmop-sta01.it.bwns.ch:/var/log/statistic/sis/$outlog"
    
    scp "$outlog" "$destfile"
    echo done