GNU 文本实用程序简介----使用日志文件(7)
时间:2005-02-04 来源:litie123
1)weblog 的结构 weblog 文件为展示文本实用程序的实际应用提供了很好的数据源。标准的 Apache 日志文件每行包含各种各样空格分隔的字段,其中每行描述对某个 Web 资源的一次访问。遗憾的是,空格有时也会出现在引号括起的字段内部,因此处理工作并不如我们想象的那样简单(如果将分隔符排除在字段之外,或许就简单了)。然而,我们必须使用所提供给我们的东西。
下面让我们研究一下在对其执行某些任务之前,我的 weblog 中的一行内容:
$ wc access-log
24422 448497 5075558 access-log
$ head -1 access-log | fmt -25
62.3.46.183 - -
[28/Dec/2003:00:00:16 -0600]
"GET /TPiP/cover-small.jpg
HTTP/1.1" 200 10146
"http://gnosis.cx/publish/programming/regular_expressions.html"
"Mozilla/4.0 (compatible;
MSIE 6.0; Windows NT 5.1)"
我们可以看到原先的文件相当大:共有 24,422 个记录。使用 fmt 来换行字段并不总是在字段边界处换行,但是引号能让您看到那些字段是什么。
br> 提取 Web 站点访问者的 IP 地址对 weblog 文件所执行的一个非常简单的任务就是提取所有站点访问者的 IP 地址。这将在常用的管道模式中组合一些实用程序(我们将研究前几个实用程序):
$ cut -f 1 -d " " access-log | sort | uniq | head -5
12.0.36.77
12.110.136.90
12.110.238.249
12.111.153.49
12.13.161.243
我们可能还想知道总共究竟有多少访问者访问过该站点:
$ cut -f 1 -d " " access-log | sort | uniq | wc -l
2820
2)统计出现次数
在上一节中,我们确定了有多少访问者访问过我们的 Web 站点,但是我们或许还想知道那 2820 个访问者中,每个对总的 24,422 次点击的贡献是多少。特别是,哪些访问者访问得最频繁呢?我们可以对一行执行:
$ cut -f 1 -d " " access-log | sort | uniq -c | sort -nr | head -5
1264 131.111.210.195
524 213.76.135.14
307 200.164.28.3
285 160.79.236.146
284 128.248.170.115 虽然这种方法有效,但是将柱状图部分引入可重用的 shell 脚本可能更为理想:
$ cat histogram
#!/bin/sh
sort | uniq -c | sort -nr | head -n
$ cut -f 1 -d " " access-log | ./histogram 3
1264 131.111.210.195
524 213.76.135.14
307 200.164.28.3 现在我们可以将面向行的任何项目列表管道输出到 histogram shell 脚本。我们希望显示的、出现得最频繁的项的数目是传递给该脚本的一个参数。
3)生成新的特殊报告
有时现有的数据文件包含我们需要的信息,但是不一定具有下游进程所需要的格式。作为一个基本的例子,假设您希望提取 weblog 的结构 中显示的 weblog 的多个字段,并以不同的顺序组合它们(同时忽略不需要的字段):
$ cut -f 6 -d " access-log > browsers
$ cut -f 1 -d " " access-log > ips
$ cut -f 2 -d " access-log | cut -f 2 -d " "
| tr "/" ":" > resources
$ paste resources browsers ips > new.report
$ head -2 new.report | tr "t" "n"
:TPiP:cover-small.jpg
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
62.3.46.183
ublishrogramming:regular_expressions.html
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
62.3.46.183
产生 resources 的行使用了两遍 cut,它们具有不同的分隔符。这是因为,对于 access-log 所认为的 REQUEST,它所包含的信息比我们希望 RESOURCE 提供的信息更多。
$ cut -f 2 -d " access-log | head -1
GET /TPiP/cover-small.jpg HTTP/1.1 我们还决定将 Apache 日志中的路径分隔符改为使用冒号路径分隔符(这是旧的 Mac OS 格式,但是我们这里只是为了展示某种类型的操作) 。
4)cut_by_regex
接下来的这个脚本将我们在本教程中所见的许多实用程序组合到一个相当复杂的管道中。假设我们知道自己想要从某个数据文件截取一个字段,但是却不知道它的字段位置。显而易见,通过可视化的检查能够提供答案,但是为了自动化不同数据文件类型的处理,我们可以截取与某个正则表达式相匹配的 任意一个 字段:
$ cat cut_by_regex
#!/bin/sh
# USAGE: cut_by_regex
cut -d "" -f
`head -n 1 | tr "" "n" | nl |
egrep | cut -f 1 | head -1`
实际上,我们可以这样使用:
$ ./cut_by_regex "([0-9]+.)" access-log " " | ./histogram 3
1264 131.111.210.195
524 213.76.135.14
307 200.164.28.3
这其中有几个部分需要作进一步的说明。反引号(backtick)是 bash 中的一种特殊语法,用于将一个命令的结果看作是另一个命令的参数。特别是,反引号中的管道产生了与作为第一个参数来提供的正则表达式相匹配的 第一个 字段编号。它是如何管理这点的呢? 首先我们仅提取数据文件的第一行;然后将指定的分隔符转换为新行字符(现在是每行一个字段);随后我们对结果行/字段编号;接着我们搜索一个具有预期模式的行;之后我们仅从该行截取字段编号;最后我们仅接受第一个匹配项(即使有多个匹配字段)。组合一个不错的管道需要费些思量,但是大多数管道都可以通过这种方式来组合。
********************END******************