grep、sed和awk都是文本处理工具,虽然都是文本处理工具单却都有各自的优缺点,一种文本处理命令是不能被另一个完全替换的,否则也不会出现三个文本处理命令了。只不过,相比较而言,sed和awk功能更强大而已,且已独立成一种语言来介绍。
awk:报告生成器,格式化以后显示。如果对处理的数据需要生成报告之类的信息,或者你处理的数据是按列进行处理的,最好使用awk。
\?:匹配其前面的字符1次或0次
\{m,n\}:匹配其前面的字符至少m次,至多n次
\{1,\}:至少一次
分组:
\(\)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
vim test1 #编辑该文件添加如下内容: He love his lover. She like her liker. He love his liker. She like her lover. He like her. She love he. [root@www ~] # grep ‘\(l..e\).*\1‘ test1 #匹配前边第一个左括号的以及与之对应的右括号的内容 He love his lover. She like her liker. [root@www ~] # grep ‘l..e‘ test1 #匹配指定的字符,中间可为任意两个字符 He love his lover. She like her liker. He love his liker. She like her lover. He like her. She love he. |
grep练习:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
1、显示 /proc/meminfo 文件中以不区分大小的s开头的行; grep -i ‘^s‘ /proc/meminfo 或者 grep ‘^[sS]‘ /proc/meminfo #[]表示匹配指定范围内的单个字符,因此也可实现不区分大小写 2、显示 /etc/passwd 中以nologin结尾的行; grep ‘nologin$‘ /etc/passwd 扩展一:取出默认shell为 /sbin/nologin 的用户列表 grep ‘/sbin/nologin‘ /etc/passwd | cut -d: -f1 或者 grep ‘/sbin/nologin‘ /etc/passwd | awk -F: ‘{print $1}‘ 或者直接使用 awk awk -F: ‘$7 ~ /nologin/{print $1}‘ /etc/passwd 扩展二:取出默认shell为 bash ,且其用户ID号最小的用户的用户名 grep ‘bash$‘ /etc/passwd | sort -n -t: -k3 | head -1 | cut -d: -f1 或者 awk -F: ‘$7 ~ /bash/{print $3,$1}‘ /etc/passwd | sort -n | head -1 | awk ‘{print $2}‘ 3、显示 /etc/inittab 中以 #开头,且后面跟一个或多个空白字符,而后又跟了任意非空白字符的行; grep ‘^#[[:space:]]\{1,\}[^[:space:]]‘ /etc/inittab 4、显示 /etc/inittab 中包含了:一个数字:(即两个冒号中间一个数字)的行; grep ‘:[0-9]:‘ /etc/inittab 5、显示 /boot/grub/grub .conf文件中以一个或多个空白字符开头的行; grep ‘^[[:space:]]\{1,\}‘ /boot/grub/grub .conf 6、显示 /etc/inittab 文件中以一个数字开头并以一个与开头数字相同的数字结尾的行; grep ‘\(^[0-9]\).*\1$‘ /etc/inittab #在RHEL5.8以前的版本中可查看到效果 7、找出某文件中的,1位数,或2位数; grep ‘\<[[:digit:]][[:digit:]]\?\>‘ /etc/inittab 或者 grep ‘\<[0-9]\{1,2\}\>‘ /etc/inittab 8、查找当前系统上名字为student(必须出现在行首)的用户的帐号的相关信息, 文件为 /etc/passwd grep ‘^student:‘ /etc/passwd 扩展:若存在该用户,找出该用户的ID号: grep ‘^student:‘ /etc/passwd | cut -d: -f3 或者 # id -u student |
1
2
3
|
ifconfig eth0| grep -oE ‘([0-9]{1,3}\.?){4}‘ | head -n 1 ifconfig eth0| awk -F: ‘/inet addr/{split($2,a," ");print a[1];exit}‘ #这里使用了awk的内置函数,如果不懂可在看完awk的介绍后再来做此题 ifconfig | grep "inet addr" | grep - v "127.0.0.1" | awk -F: ‘{print $2}‘ | awk ‘{print $1}‘ |
sed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
cp /etc/inittab ./ #复制该文件到当前目录下,这里当前处于root家目录下。 vim inittab #编辑该文件,修改此文件,内容如下所示,其内容也可参看下边的图片 # inittab is only used by upstart for the default runlevel. # #此处是一空行,没有任何字符,就光空行添加代码时会被删掉,所以这里加上备注,说明是一空交行,下面相同 # Individual runlevels are started by /etc/init/rc.conf # #此处是一空行,没有任何字符。该文件内容也看参见下边的图片 # Default runlevel. The runlevels used are: # 0 - halt (Do NOT set initdefault to this) # 1 - Single user mode # 2 - Multiuser, without NFS (The same as 3, if you do not have networking) # 3 - Full multiuser mode # 4 - unused # 5 - X11 # 6 - reboot (Do NOT set initdefault to this) # id :3:initdefault: |
用复制并修过的inittab文件作为测试文件,举几个例子:
1
|
[root@www ~] # sed ‘1,3d‘ inittab:表示删除文件的第一到第三行 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
[root@www ~] # sed ‘3,$d‘ inittab #表示删除模式空间中的第三到最后一行 # inittab is only used by upstart for the default runlevel. # [root@www ~] # sed ‘/run/d‘ inittab #表示删除被run匹配到的行 # # # 0 - halt (Do NOT set initdefault to this) # 1 - Single user mode # 2 - Multiuser, without NFS (The same as 3, if you do not have networking) # 3 - Full multiuser mode # 4 - unused # 5 - X11 # 6 - reboot (Do NOT set initdefault to this) # id :3:initdefault: [root@www ~] # sed ‘/^#/d‘ inittab #表示删除文件中以#开头的行 id :3:initdefault: [root@www ~] # sed -n ‘/^\//p‘ inittab #显示以/开头的行,因为没有这样的行,故不显示任何信息 [root@www ~] # sed ‘/^#/p‘ inittab #显示以#开头的行,可以看到被匹配到的行,均显示了两遍,这是因为sed处理时会把处理的信息输出 # inittab is only used by upstart for the default runlevel. # inittab is only used by upstart for the default runlevel. # # # Individual runlevels are started by /etc/init/rc.conf # Individual runlevels are started by /etc/init/rc.conf # # # Default runlevel. The runlevels used are: # Default runlevel. The runlevels used are: # 0 - halt (Do NOT set initdefault to this) # 0 - halt (Do NOT set initdefault to this) # 1 - Single user mode # 1 - Single user mode # 2 - Multiuser, without NFS (The same as 3, if you do not have networking) # 2 - Multiuser, without NFS (The same as 3, if you do not have networking) # 3 - Full multiuser mode # 3 - Full multiuser mode # 4 - unused # 4 - unused # 5 - X11 # 5 - X11 # 6 - reboot (Do NOT set initdefault to this) # 6 - reboot (Do NOT set initdefault to this) # # id :3:initdefault: [root@www ~] # sed -n ‘/^#/p‘ inittab #显示以#开头的行,使用-n选项表示仅显示匹配到的行 # inittab is only used by upstart for the default runlevel. # # Individual runlevels are started by /etc/init/rc.conf # # Default runlevel. The runlevels used are: # 0 - halt (Do NOT set initdefault to this) # 1 - Single user mode # 2 - Multiuser, without NFS (The same as 3, if you do not have networking) # 3 - Full multiuser mode # 4 - unused # 5 - X11 # 6 - reboot (Do NOT set initdefault to this) # |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
vim test #编辑该文件添加如下内容: Welcome to my linux! This is my world. How are you? [root@www ~] # sed ‘2r ./test‘ inittab #表示将test文件中的内容添加到inittab文件中,且从第二行往后开始添加 # inittab is only used by upstart for the default runlevel. # Welcome to my linux! #新添加的三行内容 This is my world. How are you? # Individual runlevels are started by /etc/init/rc.conf # # Default runlevel. The runlevels used are: # 0 - halt (Do NOT set initdefault to this) # 1 - Single user mode # 2 - Multiuser, without NFS (The same as 3, if you do not have networking) # 3 - Full multiuser mode # 4 - unused # 5 - X11 # 6 - reboot (Do NOT set initdefault to this) # id :3:initdefault: [root@www ~] # sed ‘1,2r ./test‘ inittab #表示将test文件中的内容添加到inittab文件中,且分别 添加在第一和第二行后边 # inittab is only used by upstart for the default runlevel. Welcome to my linux! #新添加的三行内容 This is my world. How are you? # Welcome to my linux! #新添加的三行内容 This is my world. How are you? # Individual runlevels are started by /etc/init/rc.conf # # Default runlevel. The runlevels used are: # 0 - halt (Do NOT set initdefault to this) # 1 - Single user mode # 2 - Multiuser, without NFS (The same as 3, if you do not have networking) # 3 - Full multiuser mode # 4 - unused # 5 - X11 # 6 - reboot (Do NOT set initdefault to this) # id :3:initdefault: [root@www ~] # sed ‘s/linux/LINUX/g‘ test #查找该文件中的字符串,然后替换为指定的字符串 Welcome to my LINUX! #可以看到以替换为大写的linux This is my world. How are you? [root@www ~] # sed ‘s/y.u/&r/g‘ test #查找指定的字符串,并将其替换为在其后加上r,分隔符采用/ Welcome to my linux! This is my world. How are your? [root@www ~] # sed ‘s@y.u@&r@g‘ test #意义同上,分隔符采用@ Welcome to my linux! This is my world. How are your? [root@www ~] # sed ‘s#y.u#&r#g‘ test #意义同上,分隔符采用# Welcome to my linux! This is my world. How are your? |
sed练习;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
1、删除 /etc/grub .conf文件中行首的空白符; sed -r ‘s/^[[:space:]]+//‘ /etc/grub .conf 2、替换 /etc/inittab 文件中“ id :3:initdefault:”一行中的数字为5; sed ‘s/\(id:\)[0-9]\(:initdefault:\)/\15\2/g‘ /etc/inittab 3、删除 /etc/inittab 文件中的空白行; sed ‘/^$/d‘ /etc/inittab 4、删除 /etc/inittab 文件中开头的 #号; sed ‘s/^#//g‘ /etc/inittab 5、删除某文件中开头的 #号及其后面的空白字符,但要求#号后面必须有空白符; sed ‘s/^#[[:space:]]\{1,\}//g‘ /etc/inittab 或者 sed -r ‘s/^#[[:space:]]+//g‘ /etc/inittab 6、删除某文件中以空白字符后面跟 #类的行中的开头的空白字符及# sed -r ‘s/^[[:space:]]+#//g‘ /etc/inittab 7、取出一个文件路径的目录名称; echo "/etc/rc.d/abc/edu/" | sed -r ‘s@^(/.*/)[^/]+/?@\1@g‘ #因sed支持扩展正则表达式,在扩展正则表达式中,+表示匹配其前面的字符至少1次 8、取出一个文件路径的最后一个文件名; echo "/etc/rc.d/abc/edu/" | sed -r ‘s@^/.*/([^/]+)/?@\1@g‘ |
awk是一种优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一。这种编程及数据操作语言(其名称得自于它的创始人Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母)的最大功能取决于一个人所拥有的知识。AWK提供了极其强大的功能:可以进行正则表达式的匹配,样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。实际上AWK的确拥有自己的语言:AWK程序设计语言,三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。最简单地说,AWK是一种用于处理文本的编程语言工具。我们现在使用最多的是gawk,gawk是AWK的GNU版本。
1
2
|
awk ‘BEGIN { print "line one\nline two\nline three" }‘ awk -F: ‘{ print $1, $7 }‘ /etc/passwd #等价于:awk -v FS=: ‘{print $1,$7}‘ /etc/passwd |
二、awk变量
2.1 awk内置变量之记录变量:一起来看一个示例:
1
2
3
4
5
|
vim test .txt #编辑该文件,添加如下两行信息作为示例使用 welcome to redhat linux. how are you? [root@www ~] # awk ‘BEGIN{OFS="#"} {print $1,$2}‘ test.txt #指定输出时的分隔符 [root@www ~] # awk ‘BEGIN{OFS="#"} {print $1,"hello",$2}‘ test.txt #指定输出时的分隔符,并添加显示的内容 |
1
2
3
4
5
6
7
8
9
|
[root@www ~] # awk -v FS=: -v OFS=# ‘{print $1,$7}‘ /etc/passwd #以:为字段分隔符,以#号为输出分隔符,显示该文件的第一及第七字段的值,这里仅贴出部分显示内容 root #/bin/bash bin #/sbin/nologin daemon #/sbin/nologin adm #/sbin/nologin lp #/sbin/nologin sync #/bin/sync shutdown #/sbin/shutdown halt #/sbin/halt |
1
2
|
awk ‘BEGIN{print ENVIRON["PATH"]}‘ awk ‘{print $NF}‘ test .txt |
1
2
|
[root@www ~] # awk ‘BEGIN{var="variable testing";print var}‘ #给变量赋值,并输出变量的值,下边是显示效果 variable testing |
1
2
|
[root@www ~] # awk -v var="variable testing" ‘BEGIN{print var}‘ #与上述的例子一样,显示效果如下 variable testing |
1
|
awk -F: ‘{printf "%-15s%i\n",$1,$3}‘ /etc/passwd #使用printf显示该文件中的第一列和第三列,要求第一列左对齐且占用15个字符宽度,第二列显示十进制整数,显示效果如下所示: |
四、输出重定向
使用格式:
1
|
awk -F: ‘{printf "%-15s %i\n",$1,$3 > "/dev/stderr" }‘ /etc/passwd #显示效果与上述例子一样,只不过这里是重定向到错误输出,然后显示 |
1
2
|
[root@www ~] # awk ‘BEGIN{print "A" "B"}‘ #连接A和B两个字符,使其成为一个字符串,显示效果如下所示: AB |
1
2
3
|
[root@www ~] # awk -F: ‘$1 ~ /^root/{print $1,$3,$4,$NF}‘ /etc/passwd #显示该文件中以root开头的行的第一列、第三列、第四列和最后一列,显示效果如下所示: root 0 0 /bin/bash [root@www ~] # awk -F: ‘$3>=400{printf "%-15s%-10i%s\n",$1,$3,$NF}‘ /etc/passwd #显示UID大于400的行的第一列、第三列和最后一列 |
1
2
3
4
5
|
[root@www ~] # awk -F: ‘/bash/{print $0}‘ /etc/passwd #在/etc/passwd中查找有bash的行,并显示 root:x:0:0:root: /root : /bin/bash nginx:x:496:493:: /home/nginx : /bin/bash mysql:x:495:492:: /home/mysql : /bin/bash wpuser:x:494:491:: /home/wpuser : /bin/bash |
1
2
3
|
awk -F: ‘$3>=500{printf "%-15s%s\n",$1,$3}‘ /etc/passwd awk -F: ‘$1 ~ /root/{print $1,$3}‘ /etc/passwd 等价于: awk -F: ‘$1=="root"{print $1,$3}‘ /etc/passwd |
1
2
3
4
5
6
7
8
9
|
[root@www ~] #
awk -F: ‘BEGIN{print "Username UID"}$3>=400{printf
"%-15s%s\n",$1,$3}‘ /etc/passwd
#上式表示对于该文件,在开始比较前先输出username和UID作为题头,然后,输出UID大于400的行的第一列和第三列 Username UID rtkit 499 pulse 498 saslauth 497 nfsnobody 65534 nginx 496 mysql 495 wpuser 494 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
有三中方式均可以实现,命令及显示效果如下: [root@www ~] # awk -v FS=: ‘{print $1}‘ /etc/passwd #使用-v选项和FS指定分隔符,然后显示 root bin daemon adm lp sync shutdown halt mail uucp [root@www ~] # awk -F: ‘{print $1}‘ /etc/passwd #直接使用-F选项指定分隔符,然后显示 root bin daemon adm lp sync shutdown halt mail uucp [root@www ~] # awk ‘BEGIN{FS=":"}{print $1}‘ /etc/passwd #使用BEGIN,在运行前指定分隔符,然后显示 root bin daemon adm lp sync shutdown halt mail uucp |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
[root@www ~] #
awk -F: ‘{if ($1=="root") print $1, "Admin"; else print $1, "Common
User"}‘ /etc/passwd #判断如果第一个字段是root,则显示是admin,否则显示是common
user,显示结果如下所示: root Admin bin Common User daemon Common User adm Common User lp Common User sync Common User shutdown Common User halt Common User [root@www ~] #
awk -F: ‘{if ($1=="root") printf "%-15s%s\n", $1,"Admin"; else printf
"%-15s%s\n", $1, "Common User"}‘ /etc/passwd
#显示效果同上,只不过这里使用printf,显示定义显示的格式 root Admin bin Common User daemon Common User adm Common User lp Common User sync Common User shutdown Common User halt Common User mail Common User uucp Common User [root@www ~] #
awk -F: -v sum=0 ‘{if ($3>=400) sum++}{if ($3>=400) printf
"%-15s%i\n",$1,$3}END{print "Sum = "sum;}‘ /etc/passwd
#定义变量sum=0,然后判断如果UID大于400,让sum自加,并且如果UID大于等于400的显示其用户名和UID,结束前输出sum的值 rtkit 499 pulse 498 saslauth 497 nfsnobody 65534 nginx 496 mysql 495 wpuser 494 Sum = 7 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
[root@www ~] #
awk -F: -v i=1 ‘{while (i<=7) {print $i;i++}}‘ /etc/passwd
#使用-v选项显示定义变量i=1,当i小于等于7时循环结束,然后,输出第一个字段到第七个字段,当i为7时,正好输出的是第一行的7个字段的值 root x 0 0 root /root /bin/bash [root@www ~] #
awk -F: ‘{i=1;while (i<=3) {print $i;i++}}‘ /etc/passwd
#定义变量i,先判断,当i小于等于3时,输出第一到第三个字段的值,所处理的数据时该文件中的每一行数据,而不仅仅是第一行。这里需要注意与上述命令的
区别 root x 0 bin x 1 daemon x 2 adm x 3 lp x 4 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
[root@www ~] #
awk -F: ‘{i=1;do {print $i;i++}while(i<=3)}‘ /etc/passwd
#意义同上,显示效果虽与上述相同,但与while不同的是,do-while是先执行一趟,然后再判断是否满足条件,也就是说不管条件是否满足,都会先
执行一趟;而while中如果条件不满足,则一趟也不会执行 root x 0 bin x 1 daemon x 2 adm x 3 lp x 4 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
[root@www ~] # awk -F: ‘{for(i=1;i<=3;i++) print $i}‘ /etc/passwd #使用for循环,输出各行的前三个字段 root x 0 bin x 1 daemon x 2 adm x 3 lp x 4 |
1
2
3
4
5
6
|
[root@www ~] #
awk -F: ‘$NF!~/^$/{BASH[$NF]++}END{for(A in BASH){printf
"%15s:%i\n",A,BASH[A]}}‘ /etc/passwd
#匹配最后一个字段不空的行,把最后一段当做数组下标,输出各下标的值,及各下标对应的个数,各下标的个数保存在数组中 /bin/sync :1 /bin/bash :4 /sbin/nologin :29 /sbin/halt :1 /sbin/shutdown :1 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
[root@www ~] # awk -F: ‘{if($3%2==0) next;print $1,$3}‘ /etc/passwd #UID号对2取余,如果为0,直接处理下一行,否则,输出用户名和UID号,显示效果如下所示: bin 1 adm 3 sync 5 halt 7 operator 11 gopher 13 nobody 99 dbus 81 usbmuxd 113 vcsa 69 rtkit 499 saslauth 497 postfix 89 abrt 173 rpcuser 29 mysql 495 |
1
2
|
netstat -ant | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}‘ 每出现一被/^tcp/模式匹配到的行,数组S[$NF]就加1,NF为当前匹配到的行的最后一个字段,此处用其值做为数组S的元素索引 |
1
2
3
4
5
6
7
8
9
10
11
|
[root@www ~] # awk ‘{IP[$1]++}END{for (A in IP) printf "%-20s%s\n",A,IP[A]}‘ /var/log/nginx/access.log #用法与上一个例子相同,用于统计某日志文件中IP地的访问量 172.16.32.30 3 172.16.32.50 31596 172.16.32.52 408 192.168.0.239 1886 172.16.32.0 1010 [root@www ~] # awk ‘BEGIN{A["m"]="hello";A["n"]="world";print A["m"],A["n"]}‘ #开始前对数组赋值,然后输出数组的值 hello world [root@www ~] # awk ‘BEGIN{A["m"]="hello";A["n"]="world";for (B in A) print A[B]}‘ #在开始前对数组赋值,然后使用for循环,把B当做下标,依次输出数组中的值 hello world |
1
|
netstat -ant | awk ‘/:22\>/{split($5,clients,":");IP[clients[1]]++}END{for(i in IP){print IP[i],i}}‘ | sort -rn | head -50 #显示效果如下所示: |
1
2
3
4
5
6
7
8
9
10
11
12
|
vim cfkj.sh #编辑该文件,输入如下内容: #!/bin/awk -f BEGIN{ for (i=1;i<=9;i++) { for (m=1;m<=i;m++) { printf m "*" i "=" m*i " " } print } } |
2、打印图案
1
|
awk ‘BEGIN {for(i=1;i<=4;i++) {for(j=1;j<=10-i;j++) {printf " ";}for(j=1;j<=(2*i-1);j++) {printf "*";}printf "\n";}}‘ |
1
2
|
echo 15| awk ‘{x=8; for (i=1;i<$0;i++){ for (j=1;j<=3*($0-i)-(x>0?x:0);j++) printf " " ; for (k=i;k>=1;k--) printf "%d " ,k; for (l=2;l<=i;l++) printf "%d " ,l; printf "\n" ;x--};\ for (i=1;i<=$0;i++){ for (j=1;j<=(i<=$0-10+1?3*(i-1):3*(i-1)+2-(i-$0%10-10*int(($0-10) /10 )));j++) printf " " ; for (k=$0-i+1;k>=1;k--) printf "%d " ,k; for (l=2;l<=$0-i+1;l++) printf "%d " ,l; printf "\n" }}‘ |
原文:http://www.cnblogs.com/jackydalong/p/4966298.html