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")
答案 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快得多。
您的脚本的其他一些问题:
包含所有测试的第二个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 ...等的测试,则可以完全删除。
/ $ date /,/ $ datepoint /的顺序对我来说似乎不对。 $datepoint
是第一个及时的,因此应该在$date
之前。
awk脚本包含了此更改。
#!/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