vb程序改错题题

【shell】shell脚本在大文件日志中按照时间段快速搜索日志
【shell】shell脚本在大文件日志中按照时间段快速搜索日志
问题描述:
在大流量线上服务中,日志系统会产生数量庞大的日志,动辄就是几十G。在如此之大的文件中快速搜索日志是运维人员经常遇见的问题。我们经常遇见的问题是查询一段时间内的某些条日志。比如,今天有一个访问失败了,大约是在上午9点,把这条日志找出来,然后查找失败原因。
常见处理方式及缺点:
1.如果文件比较小,100m以内使用grep、awk或者sed进行逐条匹配比较方便,但是文件非常大时,其查找效率是非常低的,运行时间长达几十分钟甚至上小时。
2.使用hadoop大数据处理,查询速度快,效率高。但是需要我们搭一套hadoop环境,需要巨大的计算量。感觉就是杀鸡焉用牛刀。
3.按照时间手动查找,使用tail -c size filename 命令 提取出一段日志,看看时间是否符合条件。如果不符合就调整size参数直到找到9点之前的时间段,然后从这里开始查起,使用grep、awk或者sed进行逐条匹配,直到找到目标日志然后ctrl+c停止,这样确实能省下很多时间,也是我以前经常用的一种方式。
解决方案:
很显然,手动查找不是一个程序员的理想解决方案,那么能不能写一个脚本自动按照时间段查找超大日志呢?常用的命令如,cat、head、tail、grep、more、less、sed、awk貌似都不能提供有效的方案。下面就是Blog介绍的方法。
下面就是我的脚本,姑且称它为探针法:
#!/bin/bash
#读入文件名
file_name=$1
#读入查询起始时间
#读取文件大小
file_size=$(stat --format=%s $file_name)
#设置探针步长,一般为文件大小的百分之一到千分之一
#如果文件大小小于步长,则size为文件大小,否则size为步长
[ $file_size -lt $step ] && size=$file_size || size=$step
#初始化探针时间
test_time=&00:00:00&
#循环检测,直到探针时间大于查询时间,停止
while [[ ${test_time} & ${start} ]]
do size=$(($size+$step))
test_time=$(dd if=$file_name skip=$(($size/10000)) ibs=10000 count=1 2&/dev/null | sed -n &2p& | awk '{print $3}')
#读取此时的查询size,使用tail -c命令即从目标时间开始查日志。
tail -c $(($file_size-$size+$step)) $file_name
执行sh find.sh filename.log 09:00:00 , 然后再使用grep等命令过滤。
解释一下,这里主要用到了dd命令:拷贝一个文件,并按照参数对其处理转换。
具体的介绍可以查看相关文档,例如,http://blog.chinaunix.net/uid--id-3416169.html
这里利用dd命令从超大文件中复制出一小块,提取出时间,也就是test_time,判断test_time是否符合条件,不符合就使size增加一个步长然后继续提取时间,直到符合条件。因为dd命令有skip选项,可以直接跳过指定大小部分截取到一段,其效率是非常高的,循环500次耗时大于1s,也就是说探针测试500次的时间是1s左右。
dd命令截取出一段日志后使用sed取出完整的一行,然后用awk取出时间戳。
&注意,设定时间为09:00:00,查询结果并不是严格从09:00:00开始的,一般会往前一点,这里受step参数影响。step越小越精确,而探针尝试次数越多。
-----------------------------------------------------分割线------------------------------------------------------------
以上第一版方法效率并不理想,而且只有开始时间,没有结束时间,所以对脚本做优化改进如下:
1.探针法改为二分查找,精确定位到目标时间
2.增加了结束时间的设置
脚本中没有为dd设置输出文件of参数,默认输出到终端,如有需要可以添加该参数。
在GetLocation方法中,使用awk提取时间戳,可根据日志格式的不同修改。
#!/bin/bash
if [[ $# -lt 3 ]];then
echo &$0 FILE STARTTIME ENDTIME&
echo &STARTTIME and ENDTIME should be in format like 09:00:00&
file_name=$1
file_size=$(stat --format=%s $file_name)
function GetLocation
echo $(dd if=$file_name skip=$(($location/10000)) ibs=10000 count=1 2&/dev/null | sed -n &2p& | awk '{print substr($3, 1,8)}')
function BinSearch
hight=$file_size
location=0
while [[ $low -le $hight ]]
mid=$((($low+$hight)/2));
location=$mid
tmp_time=`GetLocation`
if [[ $1 = $tmp_time ]]
echo $location
if [[ $1 & $tmp_time ]]
hight=$mid
if [[ $1 & $tmp_time ]]
start_local=`BinSearch $2`
echo $start_local
end_local=`BinSearch $3`
echo $end_local
length=$(($end_local-$start_local))
echo $length
dd if=$file_name bs=1000 skip=$(($start_local/1000)) count=$(($length/1000)) 2&/dev/null
原创,转发请注明。 By&
我的热门文章
即使是一小步也想与你分享博客访问: 362173
博文数量: 67
博客积分: 1169
博客等级: 少尉
技术积分: 572
注册时间:
信息量太大,每天疲于辨别信息得真伪。
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: LINUX
1、cat命令:
&&&&&功能:1)显示整个文件。
&&&&&&&&&&&&&&&&& &示例: $&cat fileName
&&&&&&&&&&&&&&2)把文件串连接后传到基本输出,如将几个文件合并为一个文件或输出到屏幕。
&&&&&&&&&&&&&&&&&& 示例: $ cat file1 file2 > file
&&&&&说明:把档案串连接后传到基本输出(屏幕或加 > fileName 到另一个档案)
&&&& cat参数详解:
&&&& -n 或 –number 由 1 开始对所有输出的行数编号
&&&& -b 或 –number-nonblank 和 -n 相似,只不过对于空白行不编号
&&&& -s 或 –squeeze-blank 当遇到有连续两行以上的空白行,就代换为一行的空白行
&&&& -v 或 –show-nonprinting
2、more命令:
&&&& 以百分比的形式查看日志。&&&&
3、less命令:
&&&& 跟more功能差不多,只不过less支持前后翻阅文件。
4、head命令:
&&&&&功能:从文本文件的头部开始查看,head 命令用于查看一个文本文件的开头部分。
&&&& 示例如下:
&&&& head example.txt 显示文件 example.txt 的前十行内容;
&&&& head -n 20 example.txt 显示文件 example.txt 的前二十行内容;
&&& &head详解:
&& & -n &&& &指定你想要显示文本多少行。
&&&& -n number && &这个参数选项必须是十进制的整数,它将决定在文件中的位置,以行为单位。
&&&& -c number && &这个参数选项必须是十进制的整数,它将决定在文件中的位置,以字节为单位。
5、tail命令:
&&&&&功能:tail 命令用于显示文本文件的末尾几行。
&&&& 示例如下:
&&&& tail example.txt 显示文件 example.txt 的后十行内容;
&&&& tail -n 20 example.txt 显示文件 example.txt 的后二十行内容;
&&&& tail -f example.txt 显示文件 example.txt 的后十行内容并在文件内容增加后,自动显示新增的文件内容。
&&&& tail -n 50 -f example.txt 显示文件 example.txt 的后50行内容并在文件内容增加后,自动显示新增的文件内容。
&&&& 注意:
&&&& 最后一条命令非常有用,尤其在监控日志文件时,可以在屏幕上一直显示新增的日志信息。
&&&&&tail详解:
&&&& -b Number 从 Number 变量表示的 512 字节块位置开始读取指定文件。&
&&&& -c Number 从 Number 变量表示的字节位置开始读取指定文件。&
&&&& -f 如果输入文件是常规文件或如果 File 参数指定 FIFO(先进先出),
&&&& 那么 tail 命令不会在复制了输入文件的最后的指定单元后终止,而是继续
&&& &从输入文件读取和复制额外的单元(当这些单元可用时)。如果没有指定 File 参数,
& && 并且标准输入是管道,则会忽略 -f 标志。tail -f 命令可用于监视另一个进程正在写入的文件的增长。&
&&&& -k Number 从 Number 变量表示的 1KB 块位置开始读取指定文件。&
&&&& -m Number 从 Number 变量表示的多字节字符位置开始读取指定文件。使用该标志提供在单字节和双字节字符代码集环境中的一致结果。&
&&&&& -n Number 从首行或末行位置来读取指定文件,位置由 Number 变量的符号(+ 或 - 或无)表示,并通过行号 Number 进行位移。&
&&&&&& -r 从文件末尾以逆序方式显示输出。-r 标志的缺省值是以逆序方式显示整个文件。如果文件大于 20,480 字节,那么-r标志只显示最后的 20,480 字节。 -r 标志只有
&& 与 -n 标志一起时才有效。否则,就会将其忽略。
阅读(53898) | 评论(2) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
大哥,你的文章跑题了,差评!!!
这几个命令经常用到
请登录后评论。新手园地& & & 硬件问题Linux系统管理Linux网络问题Linux环境编程Linux桌面系统国产LinuxBSD& & & BSD文档中心AIX& & & 新手入门& & & AIX文档中心& & & 资源下载& & & Power高级应用& & & IBM存储AS400Solaris& & & Solaris文档中心HP-UX& & & HP文档中心SCO UNIX& & & SCO文档中心互操作专区IRIXTru64 UNIXMac OS X门户网站运维集群和高可用服务器应用监控和防护虚拟化技术架构设计行业应用和管理服务器及硬件技术& & & 服务器资源下载云计算& & & 云计算文档中心& & & 云计算业界& & & 云计算资源下载存储备份& & & 存储文档中心& & & 存储业界& & & 存储资源下载& & & Symantec技术交流区安全技术网络技术& & & 网络技术文档中心C/C++& & & GUI编程& & & Functional编程内核源码& & & 内核问题移动开发& & & 移动开发技术资料ShellPerlJava& & & Java文档中心PHP& & & php文档中心Python& & & Python文档中心RubyCPU与编译器嵌入式开发驱动开发Web开发VoIP开发技术MySQL& & & MySQL文档中心SybaseOraclePostgreSQLDB2Informix数据仓库与数据挖掘NoSQL技术IT业界新闻与评论IT职业生涯& & & 猎头招聘IT图书与评论& & & CU技术图书大系& & & Linux书友会二手交易下载共享Linux文档专区IT培训与认证& & & 培训交流& & & 认证培训清茶斋投资理财运动地带快乐数码摄影& & & 摄影器材& & & 摄影比赛专区IT爱车族旅游天下站务交流版主会议室博客SNS站务交流区CU活动专区& & & Power活动专区& & & 拍卖交流区频道交流区
白手起家, 积分 9, 距离下一级还需 191 积分
论坛徽章:0
本帖最后由 fortunegzhou 于
14:34 编辑
日志格式如下
& & 01:10:11.111& & E-0& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
& & 01:11:22.222& & E-0& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
& & 01:12:33.046& & E68C& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
& & 01:13:33.046& & E68C& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
& & 01:14:33.046& & E68C& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
& & 01:15:33.046& & E68C& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
& & 01:16:11.111& & E-0& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
& & 01:17:22.222& & E-0& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
& & 01:18:33.046& & E68C& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
& & 01:19:33.046& & E68C& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
& & 01:20:33.046& & E68C& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
& & 01:21:33.046& & E68C& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
& & 01:22:11.111& & E-0& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
& & 01:25:22.222& & E-0& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
& & 01:30:33.046& & E68C& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
& & 01:32:33.046& & E68C& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
& & 01:36:33.046& & E68C& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
& & 01:40:33.046& & E68C& & 6513& & 123& & 0& & IN& & OK()& & 0& & 0& & 0& & 0& & 0& & 0
请问:如何用awk找到时间范围是& & 01:15:00.000&&到 & & 01:30:00.000 之间的日志数据
另:日志文件很大,5G以上,用什么方式查会快??
----------------------------------------(上午)更新-------------------------------------------------------
感谢大家的帮助,现报告各种写法的速度情况:
测试文件:2G, 返回的结果集在文件的末尾,大概15条
awk '{t=$1$2; if(t&=&1:15:00.000& && t&&1:20:00.000& print}' $filename
awk '$1$2 &= &1:15:00.000&&&&& $1$2 &= &1:20:00.000&' $filename
awk -vs=& 01:15:00.000& -ve=& 01:20:00.000& '{t=$1& &$2}s&=t&&t&=e' $filename
awk 'BEGIN{s=& 01:15:00.000&;e=& 01:20:00.000&}{t=$1& &$2}s&=t&&t&=e' $filename
这三种写法,执行速度最快,时间都在25s或26s
awk 'BEGIN{start=mktime(& 01 15 00&;end=mktime(& 01 20 00&}{split($1& &$2,a,&[/|.| ]&;now=mktime(a[1]& &a[2]& &a[3]& &a[4]& &a[5]& &a[6]);if(now&=start&&(now&end||(now==end&&a[7]==0))) print $0}' $filename
这种写法,速度很慢,至少5分钟没出结果,估计是mktime命令执行相当慢, 此种写法没问题,我测试过小文件,能返回正确结果
用perl脚本也比较慢,都超过200s
perl -lane 'BEGIN{$s=& 01:15:00.000&;$e=& 01:20:00.000&}{$t=&$F[0] $F[1]&;if($s lt $t && $t lt $e){print}}' $filename
perl -lane 'print if & 01:15:00.000& lt &@F[0..1]& and &@F[0..1]& lt & 01:20:00.000&' $filename
”seesea2517“的方案:没出正确的结果,估计是\t分隔符所致,我的日志文件可能不是\t分隔的,但是不管怎样,命令执行完需耗时分别如下:
cat $filename | sed -n '/\t01:15/, /\t01:20/ p'& && && && && && && && && && && && && && && & 28s
cat $filename | sed -n '/\t01:15/, /\t01:20/ /\t01:20/q;'& && &&&46s
----------------------------------------(下午)更新-------------------------------------------------------
根据cao627的提议,我试了2楼Shell_HAT的grep方式,发现速度更快,只用了2s
grep -E &\s*01:1[5-9]& ./2G.log
&&nbsp|&&nbsp&&nbsp|&&nbsp&&nbsp|&&nbsp&&nbsp|&&nbsp
论坛徽章:104
grep -E && & 01:1[5-9]|& & 01:2[0-9]& a.log复制代码
白手起家, 积分 9, 距离下一级还需 191 积分
论坛徽章:0
& & awk如何实现?
稍有积蓄, 积分 360, 距离下一级还需 140 积分
论坛徽章:1
本帖最后由 guogang225 于
18:14 编辑
awk 'BEGIN{start=mktime(& 01 15 00&);end=mktime(& 01 30 00&)}{split($1& &$2,a,&[/|:|.| ]&);now=mktime(a[1]& &a[2]& &a[3]& &a[4]& &a[5]& &a[6]);if(now&=start&&(now&end||(now==end&&a[7]==0))) print $0}' urfile复制代码回复
fortunegzhou
腰缠万贯, 积分 9062, 距离下一级还需 938 积分
论坛徽章:37
fortunegzhou awk '$1$2 &= &1:15:00.000&&&&& $1$2 &= &1:30:00.000&' file复制代码
富甲一方, 积分 45974, 距离下一级还需 4026 积分
论坛徽章:104
fortunegzhou
try them ...
# awk -vs=& 01:15:00.000& -ve=& 01:30:00.000& '{t=$1& &$2}s&t&&t&e' FILE
# awk 'BEGIN{s=& 01:15:00.000&;e=& 01:30:00.000&}{t=$1& &$2}s&t&&t&e' FILE
# perl -lane 'BEGIN{$s=& 01:15:00.000&;$e=& 01:30:00.000&}{$t=&$F[0] $F[1]&;if($s lt $t && $t lt $e){print}}' FILE
家境小康, 积分 1447, 距离下一级还需 553 积分
论坛徽章:8
学习了perl 字符串的比较方法
按你的改了改perl -lane 'print if & 01:15:00.000& lt &@F[0..1]& and &@F[0..1]& lt & 01:30:00.000&' filename复制代码回复
论坛徽章:104
fortunegzhou
& & 能否用你的数据测试一下这些方案,看看哪个最快,给大家分享一下吧
富足长乐, 积分 6046, 距离下一级还需 1954 积分
论坛徽章:49
& & 这种比较是不是awk会忽略相关的字符自动转换为数字进行比较的?应该是这样吧
论坛徽章:89
建议上述用 awk 或 perl 的,可以在找到匹配的最后一行的时候执行退出执行,即后续不再扫描,对于大文件来说应该能提高速度。
如果lz允许一点容错的话,比如多了一两行数据没关系的话,sed的示例:[seesea@UC ~]$ cat file | sed -n '/\t01:15/, /\t01:30/ p'
& && &01:15:33.046& & E68C&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:16:11.111& & E-0&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:17:22.222& & E-0&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:18:33.046& & E68C&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:19:33.046& & E68C&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:20:33.046& & E68C&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:21:33.046& & E68C&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:22:11.111& & E-0&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:25:22.222& & E-0&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:30:33.046& & E68C&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
# 加上 q 命令,在找到最后一个匹配行退出,后续如果有几G的内容就能省下很多时间啦
[seesea@UC ~]$ cat file | sed -n '/\t01:15/, /\t01:30/ /\t01:30/q;'
& && &01:15:33.046& & E68C&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:16:11.111& & E-0&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:17:22.222& & E-0&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:18:33.046& & E68C&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:19:33.046& & E68C&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:20:33.046& & E68C&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:21:33.046& & E68C&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:22:11.111& & E-0&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:25:22.222& & E-0&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0
& && &01:30:33.046& & E68C&&6513& & 123& &&&0& && & IN& && &OK()& & 0& && & 0& && & 0& && & 0& && & 0& && & 0复制代码
北京皓辰网域网络信息技术有限公司. 版权所有 京ICP证:060528号 北京市公安局海淀分局网监中心备案编号:
广播电视节目制作经营许可证(京) 字第1234号
中国互联网协会会员&&联系我们:
感谢所有关心和支持过ChinaUnix的朋友们
转载本站内容请注明原作者名及出处

我要回帖

更多关于 vf程序改错题 的文章

 

随机推荐