grep gawk

 11.2.1 grep和正则表达式 
   
  让我们首先从grep命令开始。这个命令大家应该很熟悉了,它用来在文件中查找一个 
字符串。不过,实际上,grep的处理功能要强大和复杂的多。 
   
  grep 命令的语法是 
   
   grep [模式] [文件名] 
   
  如果没有给出文件名,就缺省使用标准输入。grep每次读取一行,并且和给出的模式 
进行匹配,如果成功就把这一行会显,例如:(粗体的是我们输入的内容) 
   
  $ grep test 
   
  close 
   
  test my hand 
   
  test my hand 
 
   
  grep的“模式”也称为正则表达式,可以由各种基本的正则表达式元素构成。正则表 
达式元素主要包括下面几种: 
   
  字符串      匹配任何字符串,例如grep test表示在标准输入中1 
   
   [...]          封闭集中匹配一个字符,如:[abcde]可以匹配a,b,c,d,e 
   
  [^...]         求补集中匹配一个字符,例如[^ABC]匹配 
   
  .              匹配任意字符 
   
  /s             空白符 
   
  /S             非空白符 
   
  /d             数字 
   
  /D             非数字 
   
  /w             字母或数字 
   
  /W             非字母和数字 
   
  *        匹配任何字符 
   
  上面的形式是grep中使用的基本正则表达式,另外,还可以使用egrep,egrep是grep 
的一个扩展版本,支持下面这些扩展的正则字符串: 
   
  ^              匹配一行的开始 
   
  $              匹配一行的结尾 
   
  ( )            确定正则表达式求值顺序,和正常演算中的括号意思差不多。 
   
  (...|...|...)  或,可选项之一进行匹配,例如:(abc|dev|ghi)可以匹配abc,dev,gh 
i,而(ww|gg)do可以匹配wwdo或者ggdo。 
   
  +              一次或多次模式 
   
                 如:aba+匹配aba,abaa...不匹配ab 
   
  通常,我们有两种方法使用grep和egrep,一种是使用管道,例如我们应该熟悉的ps  
ax |grep sendmail,另一种是直接在文件中搜索对应的字符串。 
   
  grep/egrep还可以在命令行使用开关,常用的开关包括: 
   
  -b 在行前加上块号 
   
  -c 统计匹配行的个数 
   
  -n 在行前加上行号 
   
  -w 将模式解释为字符串,所有正则表达式的控制命令失效 
   
  -x 精确匹配 
   
  -r 查询文件时包含子目录 
   
  举个例子来说,我们想在/var/log/httpd/access_log中查询所有不是来自本地(192 
.168.0.1)的请求记录,可以执行: 
   
  grep –v "^192.168.0.1" /var/log/httpd/access_log 
   
  ^用来让grep 只在行首匹配。 
   
  在grep查询的时候可以使用通配符代表多个文件,例如,grep start * -r将在当前目 
录以及所有子目录的所有文件中查询start字符串。 
   
  11.2.2 gawk的使用方法 
   
  gawk是awk的一个实现,awk是一种用来处理报告等文本文件的脚本语言。不过,我们 
介绍这个产品的主要目标是用它来处理各种程序的记账文件。对于复杂的脚本,还是用 
Perl比较合适。 
   
  gawk 的主要功能是针对档案的每一行搜寻指定的 模式。,每当找到一个匹配的模式 
,gawk就会去执行你设定的动作。按照这个方式, gawk 依此方式处理输入档案的每一 
行直到输入档案结束。如果对于某个模式没有设置对应的动作,gawk将直接将这个行显 
示出来。 
   
  为了使用gawk,你通常必须先写一个awk脚本,除非模式/动作非常简单,可以在一行 
上完成。我们用一个例子来解释gawk的基本用法,首先产生一个目录列表文件: 
   
  ls –l /etc > list 
   
  现在list的内容有点像这样: 
   
  total 2164 
   
  drwxr-xr-x   3 root     root         4096 Feb 15 22:55 CORBA 
   
  -rw-r--r--   1 root     root         2045 Sep 24  1999 DIR_COLORS 
   
  -rw-r--r--   1 root     root           17 Mar 25 19:59 HOSTNAME 
   
  ………… 
   
  现在我们选择一个最简单的例子,简单地查找所有属性是drwxr-xr-x的目录文件: 
   
  gawk '/drwxr-xr-x/ {print $0}' list 
   
  将输出所有这样的目录。 
   
  这个例子看上去没有什么实际用处,因为用grep也可以做同样的动作,那么我们可以 
看一看下面这个功能: 
   
  $ gawk '$1=="-rwxr-xr-x"  {sum=sum+$5} END {print sum}' list 
   
  15041 
   
  这个是什么意思?对于所有属性是755的文件,让gawk对第五栏的数字求和。第五栏我 
们可以看到就是文件的长度,因此这个命令将显示所有属性为755的文件的总共的长度。 
   
  $n是gawk中非常重要的概念,它用来表示文本串的分栏。缺省的情况下,gawk将输入 
字符串(从文件中读入的每一行)按照分割的空格分成若干个字段,每个字段作为一个 
变量,例如有一行 
   
  my name is 3th test  
   
  那么,在awk读入这一行之后,就产生了$1到$5变量,其中$1="my",$2="is",……… 
,最后$5="test"。另外还有一个特殊的变量$0,它表示整个输入行,也就是这个字符串 
"my name is test"。另外还有一个特殊的变量NF,它表示当前行的字段的个数,在现在 
的情况下,NF应该等于5。 
   
  在某些特殊的情况下,你可能需要改变分割符的定义,这可以通过对FS赋值来完成, 
例如FS=","将分割符定义为都号而不是缺省的空格。 
   
  在一般情况下,gawk可以从命令文件中获得模式/动作,命令文件的格式很简单,就是 
直接将应该写在命令行上的模式/动作对写在文件里面,每个对构成一行,模式可以有两 
种,一种是模式匹配,也就是我们在前面解释的正则表达式,如果使用正则表达式,那 
么需要用两个/把它们夹在一起,例如/[A-Z]/表示正则表达式[A-Z]。 
   
  另一种模式是比较指令,比较指令可以用比较操作符和逻辑运算符来构成,常用的比 
较操作符有: 
   
  ==  等于  <= 不大于  ~ 按照正则表达式匹配 
   
  <  小于  >= 不小于  !~ 按照正则表达式不匹配 
   
  >  大于  != 不等于 
   
  逻辑运算符有 
   
  &&  和  ||  或  ! 非  ()括号 
 
   
  设定了模式后,就可以设置对应的动作了,在gawk中,动作必须用花括号括起来。ga 
wk能完成的动作并不多,毕竟它是一种报告分析语言。一般情况下,只要熟悉print和p 
rintf命令就足够了,print命令的格式非常简单: 
   
  print item1,item2,………… 
   
  输出时,每个项目输出一栏,中间用空格分开。一个print后面不跟着任何变量会导致 
gawk显示当前的输入行($0)。如果要输出一个字符串,使用引号把它括起来,特别是 
如果要输出一个空行,使用print ""。这里是一个例子,它将list文件的头两栏输出: 
   
          gawk '{print $1,$2}' list 
   
  由于输入的文本文件内容有多行,你在命令栏中设计的模式/动作会对每一行执行一次 
。就是: 
   
  total 2164 
   
  drwxr-xr-x 3 
   
  -rw-r--r-- 1 
   
  -rw-r--r-- 1 
   
  -rw-r--r-1 
   
  ………………… 
   
  如果你要精确地控制输出,也可以使用printf命令,这个命令的格式是: 
   
     printf format, item1, item2, ... 
   
     format参数就是C语言里面的格式控制符,例如%c,%d,%f等等。在 % 与格式控制 
字母之间可加入 modifier,modifier 是用来进一步控制输出的格式。可能的 modifie 
r 如下所示: 
   
  '-'     使用在 width 之前,指明是向左靠齐。如果'-'没有出现,则会在被指定的 
宽度向右靠齐。例如: 
   
          printf "%-4S", "foo"会印出'foo '。 
   
  'width' 这一个数字指示相对应的栏位印出时的宽度。例如: 
   
   printf "%4s","foo"     会印出' foo'。 
   
          width 的值是一个最小宽度而非最大宽度。如果一个 item 的值需要的宽度 
比 width 大,则不受 width 的影响。例如printf "%4s","foobar"将印出'foobar'。 
   
  '.prec' 此数字指定印出时的精确度。它指定小数点右边的位数。如果是要印出一个 
字串,它指定此字串最多会被印出多少个字符。 
   
  作为一种脚本语言,gawk允许使用变量,定义变量非常简单,就是直接用等号对它赋 
值。为了在gawk程序的开始处对变量赋值,gawk专门提供了BEGIN语句,这个语句将在所 
有行被读入之前执行,而且只执行一次,通常用它来执行初始化命令,例如 
   
  BEGIN { sum=0;count=0;average=0.0;} 
   
  对于变量可以使用数学表达式进行运算,运算符包括常见的加减乘除算符,以及^(乘 
方),%(取余)和著名的++,--。不过注意gawk在做除法的时候总是使用浮点除法,除了 
取余算符%。 
   
  函数 
   
  另外,gawk包含下列函数: 
   
  数学函数 
   
  atan2(x,y)      y/x的正切 
   
  cos(x)    余弦函数 
   
  sin(x)    正弦函数 
   
  int(x)    取整 
   
  log(x)    取自然对数 
   
  exp(x)    指数函数 
   
  rand(x)    生成一个0到1之间的随机数 
   
  srand()    初始化随机数发生器 
   
  systime()    返回从1970年1月1日0:00到当前时间的秒数 
   
  sqrt(x)    取x的平方根 
   
  字符串函数 
   
  index(string1,string2 ) 
   
      它会在string1 里面,寻找string2 第一次出现的地方,返回值是字串string2出 
现在字串string1 里面的位置。如果找不到,返回值为 0。 
   
      例如: 
   
          print index("peanut","an") 
   
      会印出 3。 
   
  length(string) 
   
  string字符串的长度 
   
      例如: 
   
          length("abcde") 
   
      是 5。 
   
  match(string,regexp) 
   
      match 函数会在字串 string 里面,寻找符合 regexp 的最长、最靠左边的子字 
串。返回值是 regexp 在 string 的开始位置,即 index值。这个函数会设定内部变量 
 RSTART 等於 index,内部变量RLENGTH 等於符合的子串个数。如果不符合,则会设定 
 RSTART 为0、RLENGTH 为 -1。 
   
  sprintf(format,expression1,...) 
   
  跟C语言的sprintf差不多。 
   
      例如: 
   
          sprintf("pi = %.2f (approx.)',22/7) 
   
      传回的字串为"pi = 3.14 (approx.)" 
 
   
  sub(regexp, replacement,target) 
   
      在字串 target 里面,寻找符合 regexp 的最长、最靠左边的地方,并且以字串 
 replacement 代替最左边的 regexp。 
   
      例如: 
   
          str = "water, water, everywhere" 
   
          sub(/at/, "ith",str) 
   
      结果字串str会变成 
   
      "wither, water, everywhere" 
 
   
  gsub(regexp, replacement, target) 
   
      gsub 与前面的 sub 类似。在字串 target 里面,寻找符合 regexp 的所有地方 
,以字串 replacement 代替所有的 regexp。 
   
      例如: 
   
          str="water, water, everywhere" 
   
          gsub(/at/, "ith",str) 
   
      结果字串str会变成 
   
      'wither, wither, everywhere" 
   
  substr(string, start, length) 
   
      传回字串 string 的子字串,这个子字串的长度为 length 个字符,从第 start 
 个位置开始。 
   
      例如: 
   
        substr("washington",5,3) 
   
      传回值为"ing" 
   
      如果 length 没有出现,则传回的子字串是从第 start 个位置开始至结束。 
   
      例如: 
   
          substr("washington",5) 
   
      传回值为"ington" 
   
  tolower(string) 
   
      将字串string的大写字母改为小写字母。 
   
      例如: 
   
          tolower("MiXeD cAsE 123") 
   
      传回值为"mixed case 123" 
 
   
  toupper(string) 
   
      将字串string的小写字母改为大写字母。 
   
      例如: 
   
          toupper("MiXeD cAsE 123") 
   
      传回值为"MIXED CASE 123" 
   
  其他函数 
   
  system(command) 
   
      此函式允许使用者执行作业系统的指令,执行完毕後将回到 gawk 
   
      程式。 
   
      例如: 
   
          BEGIN {system("ls")} 
   
  控制流 
   
  在gawk命令脚本中可以使用控制流,主要是if,for,while等语句,用法和C语言相当 
类似: 
 
   
    if (condition) then-body [else else-body] 
   
  如果 condition 为真(true),则执行 then-body,否则执行 else-body。 
   
      举一个例子如下: 
   
         if (x % 2 == 0) 
   
             print "x is even" 
   
          else 
   
             print "x is odd" 
 
   
      while (condition) 
   
             body 
   
  while 语句测试 condition表达式。假如 condition 为真则执行 body 的语句。一次 
执行完後,会再测试 condition,假如condition 为真,则 body 会再度被执行。这个 
过程会一直被重复直到condition 不再是真。如果 condition 第一次测试就是伪(fals 
e),则body 从没有被执行。 
   
      下面的例子会印出每个输入行的前三个栏位。 
   
          gawk '{ i=1 
   
                  while (i <= 3) { 
   
                      print $i 
   
                      i++ 
   
                  } 
   
                }' 
   
     do 
   
        body 
   
     while (condition) 
   
  这个 do loop 执行 body 一次,然後只要 condition 是真则会重复执行 body。即使 
开始时 condition 是伪,body 也会被执行一次。 
   
      下面的例子会印出每个输入记录十次。 
   
          gawk '{ i= 1 
   
                  do { 
   
                     print $0 
   
                     i++ 
   
                  } while (i <= 10) 
   
          }' 
   
    for (initialization; condition; increment) 
   
         body 
   
  此叙述开始时会执行initialization,然後只要 condition是真,它 
   
  会重复执行body与做increment 。 
   
      下面的例子会印出每个输入记录的前三个栏位。 
   
          gawk '{ for (i=1; i<=3; i++) 
   
                     print $i 
   
          }' 
   
      break 会跳出包含它的 for、while、do-while 循环的最内层。 
   
      下面的例子会找出任何整数的最小除数,它也会判断是否为质数。 
   
          gawk '# find smallest divisor of num 
   
               { num=$1 
   
                 for (div=2; div*div <=num; div++) 
   
                    if (num % div == 0) 
   
                       break 
   
                 if (num % div == 0) 
   
                    printf "Smallest divisor of %d is %d/n", num, div 
   
                 else 
   
                    printf "%d is prime/n", num }' 
   
      continue 使用于 for、while、do-while 循环内部,它会跳过循环体的剩余部分 
,立刻进行下一次循环的执行。 
   
      下面的例子会印出 0 至 20 的全部数字,但是 5 并不会被印出。 
   
          gawk 'BEGIN { 
   
               for (x=0; x<=20; x++) { 
   
                  if (x==5) 
   
                     continue 
   
                  printf ("%d",x) 
   
               } 
   
               print "" 
   
          }' 
   
      next 语句强迫 gawk 立刻停止处理目前的行而继续下一个输入行。 
   
      exit 语句会使得 gawk 程式停止执行而跳出。然而,如果 END 出现,它会去执 
行 END 的 actions。 
 
   
  自定义函数 
   
  你可以定义自己的函数,其格式是 
   
     function name (parameter-list) { 
   
         body-of-function 
   
        } 
 
   
  name 是所定义的函数名字。 parameter-list 是函数的变量列表。变量间使用逗号分 
开。 
   
  函数可以在程序的任何地方定义,不过习惯上总是定义在程序的开头部分。 
   
     下面这个例子,会将每个记录的第一个栏位之值的平方与第二个栏位之值的平方加 
起来。 
   
  {print "sum =",SquareSum($1,$2)} 
 
   
  function SquareSum(x,y) { 
   
      sum=x*x+y*y 
   
      return sum 
   

   
  如果你熟悉任何编程语言,那么掌握awk都是很轻松的事情,如果你不喜欢它,那么你 
可以参考我们下面介绍的perl。 

你可能感兴趣的:(grep gawk)