日期:2014-05-16  浏览次数:20841 次

Linux中正则表达式与文件格式化处理命令(awk/grep/sed)

一.正则表达式

1.1国际字符模式匹配或匹配模式的类名

[:alnum:] : 0-9,A-Z,a-z
[:alpha:] : A-Z,a-z
[:upper:] : A-Z
[:lower:] : a-z
[:digit:] : 0-9
[:space:] : 空格或tab键

1.2基础正则表达式

^word:待查找的字符串在行首。
word$:待查找的字符串在行尾。
. :代表一定有一个任意字符的字符。
\ :转义字符,将特殊符号的意义去除。
* :重复0个到无穷多个的前一个字符。
[list]:从字符集合的RE字符里面找出想要选取的字符,在[]当中代表一个待查找的字符;
        例如:[afg]代表a或f或g的意思。
[n1-n2]:代表想要找出的字符范围;
        eg:[0-9]表示0到9;[a-z]代表a到z。
[^list]:找出不要的字符串或范围,即找出不含list中字符串的;
        eg:[^A-Z]:代表不要非大写字母;[^t]:不要字母t。
\{n,m\}:相当于{n,m}的转义,因{的转义为\{,因}的转义为\},表示连续n到m个前一个字符。
\{n\}:相当于{n},即表示重复n个前一个字符。
\{n,\}:相当于{n,},表示连续n个以上的前一个字符。
注:正则表达式的特殊字符与一般命令行输入命令的“通配符”并不相同。在通配符中*表示0到无限多个字符。但在正则表达式中,*则是0到无穷多个前一个字符。
eg:查找以a开头的文件名的两种实现:
通配符: ls -l a*
正则表达式:ls -l | grep '^a.*' 

1.3扩张正则表达式

grep默认只支持基础正则表达式,如果使用扩展性表达式,可以使用grep -E,不过更建议直接使用egrep。egrep == grep -E。
+ :重复一个或一个以上的前一个RE字符。
    eg:egrep -n 'go+d' a.txt
    即god,good,goood,...。
? :0个或1个的前一个RE字符。
    eg: egrep -n 'go?d' a.txt
    即gd,god,good,...。
| :用或(or)的方式找出数个字符串。
    eg:egrep -n 'gd|god' a.txt
    查找含gd或good的行。
():找出‘组’字符串
    eg:egrep -E 'g(la|oo)d' a.txt
    找出glad或good的行。
()+:多个重复组的判别
    eg:egrep 'A(xyz)+C' a.txt
    开头为A,结尾为C,中间位1一个以上的xyz字符串。

注:RE:regular expression(正则表达式)。

二.awk命令

2.1awk概述

互联网中对日志分析,大多使用的是linux中的shell进行处理。此时主要使用的shell中的awk,因为awk强大的字段处理能力。下面就对其由浅入深,最后给出实例进行讲解。

首先给出一个很好的awk学习链接:http://www.cnblogs.com/chengmo/tag/awk/ 。

awk比较倾向于将一行分成数个“字段”来处理,其运行模式为:

awk '条件类型1{动作1} 条件类型2{动作2}...'   filename

注:awk主要是处理每一行的字段内的数据,而默认的字段的分隔符为空格键或tab键。

2.2awk入门

(1)eg: last -n 5 | awk '{print $1 "\t" $3}'

表示将登陆者的数据取出来,仅取前5行。其中$1表示当前行的第一个数据;$3表示当前行的第三个数据。

(2)awk是如何知道这个数据有几行几列呢?这需要下面的内置变量进行帮忙:

NF:每一行($0)的字段总数;NR:目前awk所处理的是第几行;FS:目前的分隔符,默认为空格键。

eg:在/etc/passwd当中是以冒号来作为字段分隔符的,该文件第一个字段为账号,第3个字段为UID,那下面要查询第3列小于10以下的数据,并且仅列出第一列与第三列,可以如下做:

cat /etc/passwd | awk ‘BEGIN{FS=":"} $3<10{print $1 "\t" $3}’

输出如下:

root 0

bin  1

注:BEGIN:让用户指定在第一条输入记录被处理之前所发生的动作,通常可在这里设置全局变量。END:让用户在最后一条输入记录被读取之后发生的动作。

(3)有如下的薪资表pay.txt,内容如下:

Name   1st           2st        3st

Sean   23000    24000    25000

Zhao   21000    20000    23000

Bird2   43000    42000   41000

那如何格式化输出,并能计算每个人的总额呢?

如下考虑:第一行不需要加总,只是说明(NR==1);第二行以后,有加总(NR>=2)。

命令如下:

cat pay.txt | awk '{

if(NR==1)

    printf  "%10s %10s %10s %10s %10s\n",$1,$2,$3,$4,"Total"}

NR>=2{

     total=$2+$3+$4 

     printf "%10d %10d %10d %10d %10.2f\n ",$1,$2,$3,$4,total }'

也可以这样:

cat pay.txt | awk 'NR==1{

    printf  "%10s %10s %10s %10s %10s\n",$1,$2,$3,$4,"Total"}

NR>=2{

     total=$2+$3+$4 

     printf "%10d %10d %10d %10d %10.2f\n ",$1,$2,$3,$4,total }'

(4)如何查看一个文件的最后5行:tail -n 5 a.txt

如何查看有一个文件的前5行:head -n