Tag Archives: Shell

分析日志异常的Shell脚本

经常要到线上统计日志中的异常,于是有了写下面这个脚本:

egrep -o [a-zA-Z]*Exception shop-debug.log | sort | uniq -c | sort -nr

输入结果如下:

30 UndeclaredThrowableException
22 TimeoutException
9 UploadException
9 FileUploadException
3 handleException
2 RemotingException
2 PipelineException
2 NullPointerException
1 TemplateNotFoundException
1 ResourceNotFoundException
1 ActionEventNotFoundException

找到了异常之后,肯定会关注一下这个异常,但是如果日志文件太大的话,用vi打开是比较困难的。以前我很笨地用split将日志文件分割成许多的小文件,然后查看这些小文件,找到异常信息。最近发现grep有个选项可以直接打印匹配字符串的上下若干行。 这个脚本的大概样子如下:

grep -A 50 -B 50 ActionEventNotFoundException  shop-debug.log

这行脚本的意义如下(grep –help可以看到其的说明):
Context control:
-B, –before-context=NUM print NUM lines of leading context [打印匹配行的前NUM行]
-A, –after-context=NUM print NUM lines of trailing context [打印匹配行的后NUM行]

另外发现在RHEL4中,grep 与 egrep是有区别的,grep默认不支持扩展正则表达式,正则中的分组功能没办法使用,所以要用到比较复杂的正则表达式时,还是用egrep吧。

Update:

更新一个统计访问日志的脚本,统计排名前10位的访问ip,据说这曾经是某公司的招SA的一道面试题。

-bash-3.00$ egrep -o ^\([0-9.]*\){4} 2010-03-25-taobao-access_log | sort | uniq -c | sort -nr | head -n 10
395 219.234.81.138
292 121.0.29.239
241 121.0.29.237
140 122.224.6.171
109 60.191.72.70
103 113.59.89.3
93 116.53.76.232
88 112.113.22.2
80 124.112.225.180
74 220.178.103.2

-bash-3.00$ egrep -o ^\([0-9.]*\){4} 2010-03-25-httpd-access_log | sort | uniq -c | sort -nr | head -n 10

395 219.234.81.138

292 121.0.29.239

241 121.0.29.237

140 122.224.6.171

109 60.191.72.70

103 113.59.89.3

93 116.53.76.232

88 112.113.22.2

80 124.112.225.180

74 220.178.103.2

写这个脚本时在处理如何匹配ip地址上花了不少时间,最终想到一个还算能用的正则表达式。

Awk中使用Shell的变量

昨天在写一个脚本时碰到一个问题,折腾很久后,终于找到了解决问题的方法。这段脚本中,AWK要使用Shell定义的一个变量,之前一直不得要领,Google时没有把自己的问题想清楚,所以没有找到解决方法。脚本如下:

for i in `find $1 -name \*.jar`
do
jar tvf $i| awk -F ‘/’ ‘/class/{print “‘${i}’” ” ” $NF }’ >> $classFile
done

上面的脚本中要引用外面定义的$i时,必须用”‘${i}’”的方式才能成功。AWK还是需要继续学习。

通过脚本提高效率

以前看到过一种说法,找到不两个系统完全一样的Linux用户,因为每个人都会定制些自己工具,脚本等。其中最常见的就是增加一些alias了,我觉得仅仅增加一些alias是远远不够的,除了shell本身提供的那些命令外,还有很多重复日常工作需要通过写脚本完成。最近在学python,深深为python的简洁所吸引,也发现它天生就与Linux相配,用它来写一些脚本比用shell更加灵活。

在Ubuntu上我自己摸索出了一条管理这些脚本的方法。 在/home/star/下面建了个script/bin目录,然后将这个目录加到PATH中,以后写好一个脚本后,只要放到bin下面就可以直接使用了,不用再关心路径等问题了。 我目前积累的脚本还不多,用得最多的是ssh和ftp登录dreamhost的脚本,以及一个用来批量转换文件编码的脚本。 另外还可以用这个方式来管理自己安装的一些软件的启动(我不喜欢系统apt安装的apache,jdk,mysql等东西),如argouml,apachectl,tomcat,jboss等,只要建个指向原来启动脚本的软链接就行了。通过这种方式可以很好的管理不是直接通过apt安装的软件,不需要去找每个软件的bin目录下启动了。

最后贴我写的ssh登录dreamhost的脚本:

#!/usr/bin/expect -f

spawn ssh abc@greengoblin.dreamhost.com

expect “*password”

send “XXXXXX\r”

send “\r”

expect eof

interact

一个批量下载文件的脚本

最近在重新学习英语发音,李笑来老师的博客上提供了很多相关方面的资料。 其中有些页面有很多单词发音的wav音频文件,但是我的浏览器无法播放这些音频文件。于是准备把他下载下来,但是呢一个一个地下载实在是太慢了,而且也感觉比较笨。 于是自然想到写一个脚本来干这件事情。
先去看了一下包含有音频文件的HTML页面的源码,音频文件的行非常有规律。
对于这样的文件使用Shell非常容易处理。 下面就是我写的一个简单的脚本:
#!/bin/bash
wget $1 -O wav.html
egrep “.wav\>” wav.html | awk -F ‘”‘ ‘{print $2}’ > wav.list
wget -i wav.list

怎么使用呢?只要这样就行:

star@star-desktop:~/Documents/English/pronounce/words$ ./getWav.sh http://www.xiaolai.net/index.php/archives/4047.html

其实还可以再改一改,比如把下载文件名也改成通过参数传递进去。 不过这个已经够我用了。
一转眼功夫就下载完了所有文件,实在是高效啊。
Linux下通过Shell脚本高效地完成一些繁琐的事情实在是太酷了。

有用的shell脚本

for i in `find . -name “*.java”`; do dos2unix $i ; done

这个脚本非常有用,其实可以算着是一个对某个文件夹下所有文件进行迭代操作的模板。
for i in ‘ ‘ ; 迭代出每一个文件
do
some cmd; 对每一个文件的操作
done

提供一些常用的脚本
转换编码(将gb2312转换成utf-8):
for i in `find . -name “*.java”`;

do iconv -f gb2312 -t utf-8 $i -o $i.new;

mv $i.new $i;

done

这个脚本非常有用,当你同时在使用Windows和Linux两个平台时,不同平台间文件编码的问题可以轻松解决。