这部分内容可以说是学习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