suchasplus
作家
作家
  • 铜币16枚
  • 威望11点
  • 贡献值1点
阅读:618回复:0

[灌水]今天要看这些命令!

楼主#
更多 发布于:2005-07-29 02:37
cat  tac
head  tail
od  hexdump
wc
cksum md5sum sha1sum
join cut paste split csplit


fmt nl fold
expand  unexpand

sort uniq
tsort pr


实用程序 join 相当有趣;它执行一些基本的关系运算(了解关系数据库理论的读者应该熟悉它们)。 简而言之,join 允许我们查找(排序的)记录集合之间的共有字段。 例如,您可能想知道哪些 IP 地址同时访问了您的 Web 站点和 FTP 站点,以及那些访问的相关信息(所请求的资源、时间,等等,这些信息将在日志文件中)。

为了提供一个简单的例子,假设您向不同的人发放彩色编码的出入证:供应商、合作伙伴、雇员。您希望了解哪些证件类型发放给了雇员。注意姓名是 employees 中的第一个字段,但是在 badges 中是第二个字段,字段之间全都用制表符分隔:


          $ cat employees
          Alice Aaronson  System Administrator    99 9th Street
          Bob Babuk       Programmer      7 77th Avenue
          Carol Cavo      Manager 111 West 1st Blvd.
          $ cat badges
          Red     Alice Aaronson
          Green   Alice Aaronson
          Red     David Decker
          Blue    Ernestine Eckel
          Green   Francis Fu
          $ join -1 2 -2 1 -t $'\t' badges employees
          Alice Aaronson  Red     System Administrator    99 9th Street
          Alice Aaronson  Green   System Administrator    99 9th Street

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 来换行字段并不总是在字段边界处换行,但是引号能让您看到那些字段是什么。

提取 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

统计出现次数

在上一节中,我们确定了有多少访问者访问过我们的 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 $1
          $ 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 脚本。我们希望显示的、出现得最频繁的项的数目是传递给该脚本的一个参数。    


生成新的特殊报告

有时现有的数据文件包含我们需要的信息,但是不一定具有下游进程所需要的格式。作为一个基本的例子,假设您希望提取 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
          :publish:programming: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 格式,但是我们这里只是为了展示某种类型的操作) 。


cut_by_regex

接下来的这个脚本将我们在本教程中所见的许多实用程序组合到一个相当复杂的管道中。假设我们知道自己想要从某个数据文件截取一个字段,但是却不知道它的字段位置。显而易见,通过可视化的检查能够提供答案,但是为了自动化不同数据文件类型的处理,我们可以截取与某个正则表达式相匹配的 任意一个 字段:

          $ cat cut_by_regex
          #!/bin/sh
          # USAGE: cut_by_regex <pattern> <file> <delim>
          cut -d "$3" -f             `head -n 1 $2 | tr "$3" "\n" | nl |              egrep $1 | cut -f 1 | head -1`             $2
          

实际上,我们可以这样使用:

          $ ./cut_by_regex "([0-9]+\.){3}" access-log " " | ./histogram 3
          1264 131.111.210.195
           524 213.76.135.14
           307 200.164.28.3
          

这其中有几个部分需要作进一步的说明。反引号(backtick)是 bash 中的一种特殊语法,用于将一个命令的结果看作是另一个命令的参数。特别是,反引号中的管道产生了与作为第一个参数来提供的正则表达式相匹配的 第一个 字段编号。

它是如何管理这点的呢? 首先我们仅提取数据文件的第一行;然后将指定的分隔符转换为新行字符(现在是每行一个字段);随后我们对结果行/字段编号;接着我们搜索一个具有预期模式的行;之后我们仅从该行截取字段编号;最后我们仅接受第一个匹配项(即使有多个匹配字段)。组合一个不错的管道需要费些思量,但是大多数管道都可以通过这种方式来组合。



Peter Seebach 的 "编写 Linux 实用程序的艺术: 开发有用的小命令行工具"(developerWorks,2004 年 1 月)提供了编写您自己的实用程序的指导方针和最佳实践。
http://www-128.ibm.com/developerworks/cn/linux/l-util/index.html
The history of these days will be written in blood... By crushing the armies of our enemy, by seizing the weapons they thought to turn against us, we were fighting for our very existence!
游客

返回顶部