SHELL脚本之正则表达式

  这部分内容可以说是学习shell脚本之前必学的内容。如果你这部分内容学的越好,那么你的shell脚本编写能力就会越强。所以不要嫌弃这部分内容啰嗦,也不要怕麻烦,要用心学习。一定要多加练习,练习多了就能熟练掌握了。

  在计算机科学中,正则表达式是这样解释的:它是指一个用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串。在很多文本编辑器或者其他工具里,正则表达式通常被用来检索或者替换那些符合模式的文本内容。

  其实正则表达式,只是一种思想,一种表示方法。只要我们使用的工具支持表示这种思想那么这个工具就可以处理正则表达式的字符串。常用的工具有grep、sed和awk等。

grep/egrep

  语法:grep [-cinvABC] 'word' filename

  -c:打印符合要求的行数;

  -i:忽略大小写;

  -n:在输出符合要求的行的同时连行号一起输出;

  -v:打印不符合要求的行;

  -A:后跟一个数字(有无空格都可以),例如-A2则表示打印符合要求的行以及下面的两行;

  -B:后跟一个数字,例如-B2则表示打印符合要求的行以及上面的两行;

  -C:后跟一个数字,例如-C2则表示打印符合要求的行以及上下各两行;

[root@localhost test]# grep -A2 halt /etc/passwd
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost test]# grep -B2 halt /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
[root@localhost test]# grep -C2 halt /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost test]#

  1、过滤出带有某个关键词的行,并输出行号

[root@localhost test]# grep -n 'root' /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost test]# 

  2、过滤不带某个关键词的行,并输出行号

[root@localhost test]# grep -vn 'user_' /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
2:bin:x:1:1:bin:/bin:/sbin/nologin
3:daemon:x:2:2:daemon:/sbin:/sbin/nologin
4:adm:x:3:4:adm:/var/adm:/sbin/nologin
5:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6:sync:x:5:0:sync:/sbin:/bin/sync
7:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8:halt:x:7:0:halt:/sbin:/sbin/halt
9:mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10:operator:x:11:0:operator:/root:/sbin/nologin
11:games:x:12:100:games:/usr/games:/sbin/nologin
12:ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
13:nobody:x:99:99:Nobody:/:/sbin/nologin
14:systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
15:dbus:x:81:81:System message bus:/:/sbin/nologin
16:polkitd:x:999:998:User for polkitd:/:/sbin/nologin
17:sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
18:postfix:x:89:89::/var/spool/postfix:/sbin/nologin
19:mysql:x:1000:1000::/home/mysql:/bin/bash
20:www:x:1001:1001::/home/www:/bin/bash
21:zhouguowei:x:1002:1002::/home/zhouguowei:/bin/bash
22:test:x:1003:1003:test,test'office,123456789,123654789:/home/test:/bin/bash

  3、过滤出所有包含数字的行

[root@localhost ~]# echo aaaaaaaaaaaaaaaa > test.txt
[root@localhost ~]# echo 1212222aaaaaaaaaaaa >> test.txt
[root@localhost ~]# echo 2334242423423472934792 >> test.txt
[root@localhost ~]# echo bbbbbbbbbbbbnbbb >> test.txt
[root@localhost ~]# echo 43345345fdfgdfgdfg >> test.txt
[root@localhost ~]# cat test.txt 
aaaaaaaaaaaaaaaa
1212222aaaaaaaaaaaa
2334242423423472934792
bbbbbbbbbbbbnbbb
43345345fdfgdfgdfg
[root@localhost ~]# grep [0-9] test.txt 
1212222aaaaaaaaaaaa
2334242423423472934792
43345345fdfgdfgdfg
[root@localhost ~]#

  这里提到了“[]”的应用,如果是数字的话就用[0-9]这样的形式,当然有时候也可以用这样的形式[15]即只包含1或者5,注意,它不会认为是15。如果要过滤出数字以及大小写字母则要这样[0-9a-zA-Z]。另外[]还有一种形式,就是[^字符]表示除[]内的字符之外的字符。

[root@localhost ~]# grep '[^r]oo' /etc/passwd
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
[root@localhost ~]#

  这就表示筛选包含oo字符串,但是不包含r的字符。

  4、过滤出文档中以某个字符开头或者某个字符结尾的行

[root@localhost ~]# grep '^r' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]# grep 'n$' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin

  在正则表达式中,“^”表示行的开始,“$”表示行的结尾,那么空行则表示“^$”,如果你只想筛选出非空行,则可以使用“grep -v '^$' filename”得到你想要的结果。

[root@localhost ~]# echo 12344 > test.txt 
[root@localhost ~]# echo sdfsadffa >> test.txt 
[root@localhost ~]# echo '' >> test.txt 
[root@localhost ~]# echo 'ssss32323' >> test.txt 
[root@localhost ~]# cat test.txt 
12344
sdfsadffa

ssss32323
[root@localhost ~]# grep '^$' test.txt 

[root@localhost ~]# grep -C2 '^$' test.txt 
12344
sdfsadffa

ssss32323
[root@localhost ~]# grep '^[a-zA-Z]' test.txt 
sdfsadffa
ssss32323
[root@localhost ~]#

  5、过滤任意一个字符与重复字符

[root@localhost ~]# grep 'r..t' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
[root@localhost ~]# 

  “.”表示任意一个字符,上例中,就是把符合r与o之间有两个任意字符的行过滤出来。

  “*”表示零个或多个前面的字符。

[root@localhost ~]# grep 'ooo*' /etc/passwd
root:x:0:0:root:/root:/bin/bash
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
[root@localhost ~]# 
[root@localhost ~]# grep '.*' /etc/passwd | wc -l
123
[root@localhost ~]#

  “.*”表示另个或者或者多个任意字符,空行也包含在内。

  6、指定要过滤字符出现的次数

[root@localhost ~]# grep 'o{2}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
[root@localhost ~]# 

  这里用到了“{}”,其内部为数字,表示前面的数字要重复的次数。上例中表示包含有两个o即‘oo’的行。注意,“{}”左右都要加上转义字符“”。另外,使用“{}”我们还可以表示一个范围的,具体格式是“{n1,n2}”,其中n1<n2,表示重复n1到n2次数前面的字符,n2还可以为空,则表示大于等于n1次。

  上面部分讲的grep,另外笔者常常用到egrep这个工具,简单点讲,后者是前者的扩展版本,我们可以用egrep完成grep不能完成的工作,当然了grep能完成的egrep完全可以完成。如果你嫌麻烦,egrep了解一下即可。因为grep的功能已经足够可以胜任你的日常工作了。

[root@localhost ~]# cat test.txt 
rot:x:0:0:/rot:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rooot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

1111111111111111111111111111111

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# 

  1、筛选一个或一个以上前面的字符

[root@localhost ~]# egrep 'o+' test.txt 
rot:x:0:0:/rot:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
[root@localhost ~]# egrep 'o+' test.txt 
rot:x:0:0:/rot:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
[root@localhost ~]# egrep 'oo+' test.txt 
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
[root@localhost ~]# egrep 'ooo+' test.txt 
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
[root@localhost ~]#

  2、筛选零个或者一个前面的字符

[root@localhost ~]# egrep 'o?' test.txt 
rot:x:0:0:/rot:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rooot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

1111111111111111111111111111111

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# egrep 'oo?' test.txt 
rot:x:0:0:/rot:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
[root@localhost ~]# egrep 'ooo?' test.txt 
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
[root@localhost ~]# 

  3、筛选字符串1或者字符串2

[root@localhost ~]# egrep '111|aaa' test.txt 
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# 

  4、egrep中的“()”的应用

[root@localhost ~]# egrep 'r(oo)|(at)o' test.txt 
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
[root@localhost ~]# 

  用“()”表示一个整体,例如(oo)+就表示1个oo或者多个oo。

[root@localhost ~]# egrep '(oo)+' test.txt 
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
[root@localhost ~]# 

sed工具的使用

   grep工具的功能其实还不够强大,其实说白看,grep实现的只是查找功能,而他却不能实现把查找的内容替换掉。sed工具以及下面要讲的awk工具就能实现把替换的文本输出到屏幕上的功能了,而且还有其他更丰富的功能。sed和awk都是流式编辑器,是针对文档的行来操作的。

  1、打印某行sed -n 'n'p filename单引号内的n是一个数字,表示第几行

[root@localhost ~]# cat test.txt 
rot:x:0:0:/rot:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# sed -n '2'p test.txt 
operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]# 

  2、打印多行,打印整个文档用 -n '1,$'p

[root@localhost ~]# sed -n '2,4'p test.txt 
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
[root@localhost ~]# sed -n '1,$'p test.txt 
rot:x:0:0:/rot:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# 

  3、打印包含某个字符的行

[root@localhost ~]# sed -n '/root/'p test.txt 
operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]# 

  上面grep中使用的特殊字符,如“^”、“$”,“.”、“*”等,同样也能在sed中使用。

[root@localhost ~]# sed -n '/^1/'p test.txt 
1111111111111111111111111111111
[root@localhost ~]# sed -n '/in$/'p test.txt 
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
[root@localhost ~]# sed -n '/r..t/'p test.txt 
operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]# sed -n '/ooo*/'p test.txt 
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
[root@localhost ~]#

  4、-e可以实现多个行为

[root@localhost ~]# sed -e '1'p  -e '/111/'p -n test.txt 
rot:x:0:0:/rot:/bin/bash
1111111111111111111111111111111
[root@localhost ~]# 

  5、删除某行或者多行

[root@localhost ~]# sed '1'd test.txt 
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# sed '1,3'd test.txt 
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# sed '/oot/'d test.txt 
rot:x:0:0:/rot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# 

  “d”这个字符就是删除的动作了,不仅可以删除指定的单行以及多行,而且还可以删除匹配某个字符的行,另外还可以删除从某一行到文档末尾。

[root@localhost ~]# sed '2,$'d test.txt 
rot:x:0:0:/rot:/bin/bash
[root@localhost ~]# 

  6、替换字符或字符串

[root@localhost ~]# sed '1,2s/ot/to/g' test.txt 
rto:x:0:0:/rto:/bin/bash
operator:x:11:0:operator:/roto:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# 

  上例中的“s”就是替换的命令,“g”为本行中全局替换,如果不加“g”,只换该行中出现的第一次。

  除了可以使用“/”外,还可以使用其他特殊字符,例如“#”或者“@”都没有问题。

[root@localhost ~]# sed '1,2s#ot#to#g' test.txt 
rto:x:0:0:/rto:/bin/bash
operator:x:11:0:operator:/roto:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# sed '1,2s@ot@to@g' test.txt 
rto:x:0:0:/rto:/bin/bash
operator:x:11:0:operator:/roto:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# 

  现在思考一下,如何删除文档中的所有数字或者字母?

[root@localhost ~]# sed '1,$s/[0-9]//g' test.txt 
rot:x:::/rot:/bin/bash
operator:x:::operator:/root:/sbin/nologin
operator:x:::operator:/rooot:/sbin/nologin
roooot:x:::/rooooot:/bin/bash

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# sed 's/[0-9]//g' test.txt 
rot:x:::/rot:/bin/bash
operator:x:::operator:/root:/sbin/nologin
operator:x:::operator:/rooot:/sbin/nologin
roooot:x:::/rooooot:/bin/bash

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# 
[root@localhost ~]# sed 's/[a-zA-Z]//g' test.txt 
::0:0:/://
::11:0::/://
::11:0::/://
::0:0:/://
1111111111111111111111111111111

[root@localhost ~]# sed 's/[0-9a-zA-Z]//g' test.txt 
::::/://
:::::/://
:::::/://
::::/://


[root@localhost ~]# 

  7、调换两个字符串的位置

[root@localhost ~]# sed 's/(rot)(.*)(bash)/321/' test.txt
bash:x:0:0:/rot:/bin/rot
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# 

  这就需要解释一下了,上例中用“()”把所想要替换的字符括起来成为一个整体,因为括号在sed中属于特殊字符,所以需要在前面加上转义字符“”,替换时则写成“1”,“2”,“3”的形式。

   在某一行前或者后增加指定内容。

[root@localhost ~]# sed 's/^.*$/123&/' test.txt 
123rot:x:0:0:/rot:/bin/bash
123operator:x:11:0:operator:/root:/sbin/nologin
123operator:x:11:0:operator:/rooot:/sbin/nologin
123roooot:x:0:0:/rooooot:/bin/bash
1231111111111111111111111111111111
123aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# 
[root@localhost ~]# sed 's/^.*/&123/' test.txt 
rot:x:0:0:/rot:/bin/bash123
operator:x:11:0:operator:/root:/sbin/nologin123
operator:x:11:0:operator:/rooot:/sbin/nologin123
roooot:x:0:0:/rooooot:/bin/bash123
1111111111111111111111111111111123
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa123
[root@localhost ~]# 

  8、直接修改文件内容

  sed -i 's/:/#/g' test.txt,这样就可以直接更改test.txt文件的内容了。由于这个命令可以直接把文件修改,所以在修改前最好先复制一下文件以免改错。

sed练习

  1、把/etc/passwd复制到/root/test.txt,用sed打印所有行;

[root@localhost ~]# cp /etc/passwd /root/test.txt;sed -n '1,$'p test.txt

  2、打印test.txt的3到10行;

[root@localhost ~]# sed -n '3,10'p test.txt

  3、打印test.txt中包含‘root’的行;

[root@localhost ~]# sed -n '/root/'p test.txt

  4、删除test.txt的15行以及后边所有行;

[root@localhost ~]# sed '15,$'d test.txt

  5、删除test.txt中包含‘bash’的行;

[root@localhost ~]# sed '/bash/'d test.txt

  6、替换test.txt中的‘root’为‘toor’;

[root@localhost ~]# sed 's/root/toor/g' test.txt

  7、替换test.txt中的‘/sbin/nologin’为‘/bin/login’;

[root@localhost ~]# sed 's//sbin/nologin//bin/login/g' test.txt 
[root@localhost ~]# sed 's#/sbin/nologin#/bin/login#g' test.txt

  8、删除test.txt中5到10行中的所有数字;

[root@localhost ~]# sed '5,10s/[0-9]//g' test.txt

  9、删除test.txt中所有特殊字符(除了数字以及大小写字母);

[root@localhost ~]# sed 's/[^0-9a-zA-Z]//g' test.txt 

  10、把test.txt中第一个单词和最后一个单词调换位置;

[root@localhost ~]# sed 's/(^[a-zA-Z][a-zA-Z]*)([^a-zA-Z].*)([^a-zA-Z])([a-zA-Z][a-zA-Z]*$)/4231/' test.txt

  11、把test.txt中出现的第一个数字和最后一个单词替换位置;

[root@localhost ~]# sed 's#([^0-9][^0-9]*)([0-9][0-9]*)([^0-9].*)([^a-zA-Z])([a-zA-Z][a-zA-Z]*$)#15342#' test.txt

  12、把test.txt中第一个数字移动到行的末尾;

[root@localhost ~]# sed 's#([^0-9][^0-9]*)([0-9][0-9]*)([^0-9].*$)#132#' test.txt

  13、在test.txt20行到末尾行最前面加‘aaa’;

[root@localhost ~]# sed '20,$s/^.*$/aaa:&/' test.txt

awk工具使用

  上面也提到了awk和sed一样是流式编辑器,也是针对文档中的行来操作的,一行一行的去指向。awk比sed更加强大,他能做到sed能做到的,同样也能做到sed不能做到的。awk工具其实是很复杂的,有专门的书籍来介绍它的应用。

  1、截取文档中的某个段 

[root@localhost ~]# head -n2 test.txt | awk -F ':' '{print $1}'
root
bin
[root@localhost ~]# 

  解释一下,-F选项的作用是指定分隔符,如果不加-F指定,则以空格或者tab为分隔符。

[root@localhost ~]# head -n2 /etc/inittab 
# inittab is no longer used when using systemd.
#
[root@localhost ~]# head -n2 /etc/inittab | awk '{print $2,$3}'
inittab is
 
[root@localhost ~]# 

  print为打印动作,用来打印某个字段。$1为第一个字段,$2为第二个字段,以此类推,有一个特殊的那就是$0,它代表整行。

[root@localhost ~]# head -n2 test.txt | awk -F ':' '{print $0}'
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@localhost ~]# 

  注意awk的格式,-F后紧跟单引号,然后里面为分隔符,print的动作要用‘{}’括起来,否则会报错。print还可以打印自定义的内容,但是自定义的内容要用双括号括起来。

[root@localhost ~]# head -n2 test.txt | awk -F ':' '{print $1"@"$2"@"$3}'
root@x@0
bin@x@1
[root@localhost ~]# 

  2、匹配字符或字符串

[root@localhost ~]# awk '/root/' test.txt 
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]# 

  跟sed很类似吧,不过还有比sed更强大的匹配

[root@localhost ~]# awk -F ':' '$1~/root/' test.txt 
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]# 

  可以让某个段去匹配,这里的‘~’就是匹配的意思。

[root@localhost ~]# awk -F ':' '/root/ {print $3} /test/ {print $3}' test.txt 
0
11
1003
[root@localhost ~]# 

  awk还可以多次匹配,如上例中匹配完root,再匹配test,还可以只打印所匹配的字段。

[root@localhost ~]# awk -F ':' '$1~/root/ {print $1}' test.txt 
root
[root@localhost ~]#

  3、条件操作符

[root@localhost ~]# awk -F ':' '$3=="0"' test.txt 
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]# 

  awk中是可以逻辑符号判断的,比如‘==’就是等于,也可以理解为“精确匹配”。另外也有“>”、“>=”、“<”、“<=”、“!=”等等,值得注意的是,即使$3为数字,awk也不会把它当做是一个数字。所以不要妄图拿$3当做数字和数字做比较。

[root@localhost ~]# cat test.txt | awk -F ':' '$3>="500"'
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
[root@localhost ~]#

  这样是得不到我们想要对的效果的。这里只是字符与字符之间的比较,‘6’是>‘500’的。

[root@localhost ~]# cat test.txt | awk -F ':' '$7!="/sbin/nologin"'
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mysql:x:1000:1000::/home/mysql:/bin/bash
www:x:1001:1001::/home/www:/bin/bash
zhouguowei:x:1002:1002::/home/zhouguowei:/bin/bash
test:x:1003:1003:test,test'office,123456789,123654789:/home/test:/bin/bash

  上例中用的是‘!=’即不匹配。

[root@localhost ~]# awk -F ':' '$3<$4' test.txt 
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
[root@localhost ~]# 

  另外还可以使用‘&&’和‘||’表示“并且”和“或者”的意思。

[root@localhost ~]# awk -F ':' '$3>"5" && $3<"7"' test.txt 
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
[root@localhost ~]#
[root@localhost ~]# awk -F ':' '$3<"1" || $3 >"8"' test.txt 
root:x:0:0:root:/root:/bin/bash
nobody:x:99:99:Nobody:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
[root@localhost ~]# 

  4、awk的内置变量

  NF:用分隔符分割后一共多少段;

  NR:行数

[root@localhost ~]# head -n5 test.txt | awk -F ':' '{print NF}'
7
7
7
7
7
[root@localhost ~]# head -n5 test.txt | awk -F ':' '{print $NF}'
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
[root@localhost ~]#

  上例中,打印总共的段数以及最后一段的值。

[root@localhost ~]# awk 'NR>=20' test.txt 
www:x:1001:1001::/home/www:/bin/bash
zhouguowei:x:1002:1002::/home/zhouguowei:/bin/bash
test:x:1003:1003:test,test'office,123456789,123654789:/home/test:/bin/bash
user_00:x:1004:100::/home/user_00:/bin/bash
user_01:x:1005:100::/home/user_01:/bin/bash
user_02:x:1006:100::/home/user_02:/bin/bash
user_03:x:1007:100::/home/user_03:/bin/bash
user_04:x:1008:100::/home/user_04:/bin/bash
user_05:x:1009:100::/home/user_05:/bin/bash
user_06:x:1010:100::/home/user_06:/bin/bash
user_07:x:1011:100::/home/user_07:/bin/bash
user_08:x:1012:100::/home/user_08:/bin/bash
user_09:x:1013:100::/home/user_09:/bin/bash
user_10:x:1014:100::/home/user_10:/bin/bash
user_11:x:1015:100::/home/user_11:/bin/bash

  可以使用NR作为条件,来打印指定的行。

[root@localhost ~]# awk -F ':' 'NR>=20 && $1~/test/' test.txt 
test:x:1003:1003:test,test'office,123456789,123654789:/home/test:/bin/bash
[root@localhost ~]#

  5、awk中的数学运算

[root@localhost ~]# head -n5 test.txt | awk -F ':' '$1="root"'
root x 0 0 root /root /bin/bash
root x 1 1 bin /bin /sbin/nologin
root x 2 2 daemon /sbin /sbin/nologin
root x 3 4 adm /var/adm /sbin/nologin
root x 4 7 lp /var/spool/lpd /sbin/nologin
[root@localhost ~]#
[root@localhost ~]# head -n2 test.txt | awk -F ':' '{$7=$3+$4;print $3,$4,$7}'
0 0 0
1 1 2
[root@localhost ~]# 

  当然还可以计算某个段的总和。

[root@localhost ~]# cat test.txt | awk -F ':' '{(tot+=$3)};END {print tot}'
112067
[root@localhost ~]# 

  这里的END做注意一下,表示所有的行都已经执行,这是awk特有的语法,其实awk连同sed都可以写成一个脚本文件,而且有它们特有的语法,在awk中使用if判断、for循环都是可以的。

[root@localhost ~]# awk -F ':' '{if ($1=="root") print $0}' test.txt 
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]# 

awk练习

  1、用awk打印整个test.txt;

[root@localhost ~]# awk '{print $0}' test.txt

  2、查找所有包含‘bash’的行;

[root@localhost ~]# awk '/bash/' test.txt

  3、用‘:’作为分隔符,查找第三段等于0的行;

[root@localhost ~]# awk -F ':' '$3==0' test.txt

  4、用‘:’作为分隔符,查找第一段为root的行,并把该段的root换成toor;

[root@localhost ~]# awk -F':' '$1=="root"' test.txt |sed 's/root/toor/'

  5、用‘:’作为分隔符,打印最后一段;

[root@localhost ~]# awk -F ':' '{print $NF}' test.txt 

  6、打印行数大于20的所有行;

[root@localhost ~]# awk 'NR>20' test.txt

  7、用‘:’作为分隔符,打印所有第三段小于第四段的行;

[root@localhost ~]# awk -F ':' '$3<$4' test.txt

  8、用‘:’作为分隔符,打印第一段以及最后一段,并且中间中‘@’连接;

[root@localhost ~]# awk -F ':' '{print $1"@"$NF}' test.txt 

  9、用‘:’作为分隔符,把整个文档的第四段相加,求和;

[root@localhost ~]# awk -F ':' '{(tot+=$4)};END {print tot}' test.txt

  

  

原文地址:https://www.cnblogs.com/zhouguowei/p/9516043.html