shell 字符串处理和数值排序

1,496 阅读3分钟

最近一个哥们的需求是对日志里面的数据做一下监控,要求是日志里面的某个字段的值,并求这一值得最大最小值。

日志样例:

10:46:13.840 [Thread-11] WARN  c.c.b.s.s.c.Status - TPS=137504, delay=7,40023ms, avgTPS=137536, avgDelay=7,400194ms, objs=137536, totalTime=1s
10:46:14.840 [Thread-10] WARN  c.c.b.s.s.c.Status - TPS=138896, delay=7,31168ms, avgTPS=138304, avgDelay=7,355904ms, objs=276640, totalTime=2s
10:46:15.840 [Thread-12] WARN  c.c.b.s.s.c.Status - TPS=139904, delay=7,26450ms, avgTPS=138864, avgDelay=7,326106ms, objs=416592, totalTime=3s
10:46:16.840 [Thread-12] WARN  c.c.b.s.s.c.Status - TPS=143504, delay=7,08871ms, avgTPS=140044, avgDelay=7,265344ms, objs=560176, totalTime=4s
10:46:17.840 [Thread-12] WARN  c.c.b.s.s.c.Status - TPS=143776, delay=7,07661ms, avgTPS=140790, avgDelay=7,226796ms, objs=703952, totalTime=5s
10:46:18.840 [Thread-12] WARN  c.c.b.s.s.c.Status - TPS=143376, delay=7,09954ms, avgTPS=141224, avgDelay=7,205253ms, objs=847344, totalTime=6s

需要获得得是avgDelay这一列的数值 首先需要做字符串匹配

line=`echo ${line#*=}`
line=`echo ${line%m*}`
line=`echo ${line/,/.}`

上面的含义是:

  1. echo ${line#*=} # 号是运算符 *= 表示从左边开始删除第一个 = 号及左边的所有字符
  2. echo ${line%m*} %号是运算符 m* 表示从右边开始,删除第一个 m 号及右边的字符
  3. echo ${line/,/.} /表示单词匹配,号 用.号代替

其他的相关符号使用可见下

>假设有变量 var=http://www.aaa.com/123.htm.
>
>1. # 号截取,删除左边字符,保留右边字符。
>
>echo ${var#*//}
> 其中 var 是变量名,# 号是运算符,*// 表示从左边开始删除第一个 // 号及左边的所有字符
>即删除 http://
>结果是 :www.aaa.com/123.htm
>
>2. ## 号截取,删除左边字符,保留右边字符。
>
>echo ${var##*/}
> 
>
>##*/ 表示从左边开始删除最后(最右边)一个 / 号及左边的所有字符
>即删除 http://www.aaa.com/
>
>结果是 123.htm
>
>3. %号截取,删除右边字符,保留左边字符
>
>echo ${var%/*}
> 
>
>%/* 表示从右边开始,删除第一个 / 号及右边的字符
>
>结果是:http://www.aaa.com
>
>4. %% 号截取,删除右边字符,保留左边字符
>
>echo ${var%%/*}
> %%/* 表示从右边开始,删除最后(最左边)一个 / 号及右边的字符
>结果是:http:
>
>5. 从左边第几个字符开始,及字符的个数
>
>echo ${var:0:5}
> 
>
>其中的 0 表示左边第一个字符开始,5 表示字符的总个数。
>结果是:http:
>
>6. 从左边第几个字符开始,一直到结束。
>
>echo ${var:7}
> 
>
>其中的 7 表示左边第8个字符开始,一直到结束。
>结果是 :www.aaa.com/123.htm
>
>7. 从右边第几个字符开始,及字符的个数
>
>echo ${var:0-7:3}
> 
>
>其中的 0-7 表示右边算起第七个字符开始,3 表示字符的个数。
>结果是:123
>
>8. 从右边第几个字符开始,一直到结束。
>
>echo ${var:0-7}
> 
>
>表示从右边第七个字符开始,一直到结束。
>结果是:123.htm
>
>注:(左边的第一个字符是用 0 表示,右边的第一个字符用 0-1 表示)

> 一个替换的例子:
str="apple, tree, apple tree"  
echo ${str/apple/APPLE}   # 替换第一次出现的apple  
echo ${str//apple/APPLE}  # 替换所有apple  
echo ${str/#apple/APPLE}  # 如果字符串str以apple开头,则用APPLE替换它  
echo ${str/%apple/APPLE}  # 如果字符串str以apple结尾,则用APPLE替换它  

故读取文件并匹配替换的代码如下:

#获取文件名
logpath=$1

echo "raw data:"
for line in `cat $logpath`
do
#匹配avgDelay字符串
if [[ ${line} == *"avgDelay"* ]];then
#截取数字并处理
line=`echo ${line#*=}`
line=`echo ${line%m*}`
line=`echo ${line/,/.}`
echo $line >> logmidfile.txt
fi
done

对于排序 Linux许多发行版提供sort命令以行为单位对文本进行排序

一个以数字进行排序的例子:sort -n sort.txt # sort.txt

1 mac 2000 3 winxp 4000 2 linux 1000 4 win7 1000 2 linux 1000

结果: 1 mac 2000 2 linux 1000 2 linux 1000 3 winxp 4000 4 win7 1000

故全部实现代码如下:

#!/bin/bash
###################################################################
#*名称     --%@NAME:日志收集排序
#*功能描述 --%@COMMENT: 
#*执行周期 --%@PERIOD:
#*参数     --%@PARAM:v_hour 帐期 YYYYMMDDHH
#*参数     --%@PARAM:logpath 日志路径
#*创建人   --%@CREATOR:
#*创建时间 --%@CREATED_TIME:2019-07-31
#*层次     --%@LEVEL:
#*备注     --%@REMARK:
#*修改记录 --%@MODIFY:
####################################################################
#参数要求,一共需要1个参数
if [ "$#" -ne "1" ]; then
        echo "必须是1个参数logpath"
        exit 1
fi

#获取文件名
logpath=$1
#删除中间文件
rm -rf logmidfile.txt

echo "raw data:"
for line in `cat $logpath`
do
#匹配avgDelay字符串
if [[ ${line} == *"avgDelay"* ]];then
#截取数字并处理
line=`echo ${line#*=}`
line=`echo ${line%m*}`
line=`echo ${line/,/.}`
echo $line >> logmidfile.txt
fi
done

#创建数组
array=(0)
#创建计数标识
le=0 
#排序文件
sort logmidfile.txt -n
echo "sort is done:"
for line2 in `cat logmidfile.txt`
do
echo $line2
array[le]=$line2
le=`expr $le + 1` #标识++
done

echo "max:${array[0]}  min:${array[(($le-1))]}"


#删除中间文件
rm -rf logmidfile.txt

参考资料:

www.cnblogs.com/delav/p/995…

www.cnblogs.com/gaochsh/p/6…

www.linuxidc.com/Linux/2019-…

www.cnblogs.com/zwgblog/p/6…

www.cnblogs.com/gaochsh/p/6…