2.正则表达式
定义:它使用单个字符串来描述或匹配一系列符合某个句法规则的字符串。在很多文本编辑器或其它工具中,正则表达式通常用来检索和替换某个模式的文本内容。
其实正则表达式只是一种思想、一种方法。只要我们使用的工具支持这种方法,那么这个工具就可以处理正则表达试的字符串。常用的工具有grep、sed、awk等,其中grep、sed和awk都是对文本的行进行操作。
2.1 grep/egrep工具的使用
该命令的格式为:grep [-cnvABC] 'worf' filename,其常用的选项如下所示:
-c:表示打印符合要求的行数。
-i:表示忽略大小写。
-n:表示输出符合要求的行机器行号。
-v:表示打印不符合要求的行。
-A:后面跟一个数字(有无空格都可以),例如-A2表示打印符合要求的行以及下面两行。
-B:后面跟一个数字,例如-B2表示打印符合要求的行以及上面两行。
-C:后面跟一个数字,例如-C2表示打印符合要求的行以及上下各两行。
首先看看-A、-B和-C这3个选项的用法。
-A2会把包含halt的行以及这行下面的两行都打印出来:
[root@localhost ~]# 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
-B2:会把包含halt的行以及这行上面的两行都打印出来:
[root@localhost ~]# 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
-C2会把包含halt的行以及上下各两行都打印出来:
[root@localhost ~]# 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
2.1.1过滤出带有某个关键词的行,并输出行号
示例命令如下:
[root@localhost ~]# grep -n 'root' /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin
2.1.2过滤出不带有某个关键词的行,并输出行号
示例命令如下:
[root@localhost ~]# grep -nv 'root' /etc/passwd
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
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:chrony:x:998:996::/var/lib/chrony:/sbin/nologin
2.1.3过滤出包含数字的行
示例命令如下:
[root@localhost ~]# grep '[0-9]' /etc/inittab
multi-user.target: analogous to runlevel 3
graphical.target: analogous to runlevel 5
2.1.4过滤出所有不包含数字的行
[root@localhost ~]# grep -v '[0-9]' /etc/inittab
inittab is no longer used when using systemd.
ADDING CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
Ctrl-Alt-Delete is handled by /usr/lib/systemd/system/ctrl-alt-del.target
systemd uses 'targets' instead of runlevels. By default, there are two main targets:
To view current default target, run:
systemctl get-default
To set a default target, run:
systemctl set-default TARGET.target
2.1.5过滤掉所有空行和以#开头的行
示例命令如下:
[root@localhost ~]# cat /etc/grep.txt
aaaa
bbb
#ccc
dddd
[root@localhost ~]# grep -v '^#' /etc/grep.txt |grep -v '^$'
aaaa
bbb
dddd
正则表达式中,^表示行的开始,表示行的结尾,那么空行就可以用\^表示。如何打印出不以英文字母开头的行呢?举个例子:
[root@localhost ~]# cat /etc/grep.txt
2aaaa
b1bb
123
#ccc
2222
dddd
AAAAA
333
[root@localhost ~]# grep -v '^[a-zA-Z]' /etc/grep.txt
2aaaa
123
#ccc
2222
333
[root@localhost ~]# grep '^[^a-zA-Z]' /etc/grep.txt
2aaaa
123
#ccc
2222
333
[root@localhost ~]# grep '[^a-zA-Z]' /etc/grep.txt
2aaaa
b1bb
123
#ccc
2222
333
[^字符]表示除[]以外的字符。注意把^写到括号里跟括号外是有区别的。前面提到过[]的应用,如果是数字就用[0-9]这样的形式(当遇到类似[15]的形式时表示只含有1或者5)。如果要过滤数字以及大小写字母,则要写成类似[0-9a-zA-Z]的形式。
2.1.6过滤出任意一个字符和重复字符
示例命令如下:
[root@localhost ~]# grep 'r.o' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
.表示任意一个字符。上海李忠,r.o表示把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
*表示零个或多个*前面的字符。上例中,ooo*表示oo、ooo、oooo或者更多的o。
[root@localhost ~]# grep '.*' /etc/passwd |wc -l
19
*表示零个或者多个任意字符,空行也包括在内,他会把/etc/passwd文件里面所有行都匹配到。
2.1.7指定要过滤出的字符出现次数
示例命令如下:
[root@localhost ~]# grep '0\{2\}' /etc/passwd
games:x:12:100:games:/usr/games:/sbin/nologin
这里用到了符号{},其内部位数字,表示前面的字符要重复的次数。需要强调的是,{}左右都需要加上转义字符\。另外,使用"{}"还可以表示一个范围,具体格式{n1,n2},其中n1<n2,表示重复n1到n2次前面的字符,n2还可以为空,这是表示大于等于n1次。
除grep工具外,还有egrep这个工具,后者是前者的扩展版本,可以完成grep不能完成的工作。下面介绍下不同的用法为了实验方便,把grep.txt编辑成了如下内容:
[root@localhost ~]# vi /etc/grep.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
2.1.8过滤出一个或多个指定的字符
示例命令如下:
[root@localhost ~]# egrep 'o+' /etc/grep.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+' /etc/grep.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+' /etc/grep.txt
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
和grep不同的是,egrep使用的是符号+,他表示匹配1个或多个+前面的字符,这个"+"是不支持被grep直接使用的。包括上面的{},也是可以直接被egrep使用,而不用加\转义。示例如下:
[root@localhost ~]# egrep 'o{2}' /etc/grep.txt
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
2.1.9过滤出零个或一个指定字符
示例如下:
[root@localhost ~]# egrep 'o?' /etc/grep.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 'ooo?' /etc/grep.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 'oooo?' /etc/grep.txt
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
2.1.10过滤出字符串1或者字符串2
示例命令如下:
[root@localhost ~]# egrep 'aaa|111|ooo' /etc/grep.txt
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
2.1.11egrep中()的应用
示例命令如下:
[root@localhost ~]# egrep 'r(oo|at)o' /etc/grep.txt
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
这里用()表示一个整体,上例中会把包含rooo或者rato的行过滤出来,林外也可以吧()和其他符号组合在一起,例如(oo)+就表示1个或者多个oo。如下所示:
[root@localhost ~]# egrep '(oo)+' /etc/grep.txt
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
2.2sed工具的使用
其实grep工具的功能还不够强大,它实现的只是查找功能,而不能把查找的能容替换。以前用vim操作文档的时候,可以查找也可以替换,但只限于在文本内部操作,而不能输出到屏幕上。sed工具以及后面要介绍的awk工具就能把替换的文本输出到屏幕上,而且还有其他更丰富的功能。sed和awk都是流式编辑器,是针对文档的行来操作的。
2.2.1打印某行
sed的格式为:sed -n 'n'p filename ,单引号内的n是一个数字,表示第几行。-n选项的作用是只显示我们要打印的行,无关紧要的内容不显示。示例命令如下:
[root@localhost ~]# sed -n '2'p /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
你可以去掉-n选项对比一下差异。要想把所有行都打印出来,可以使用命令sed -n '1,$'p filename,如下所示:
[root@localhost ~]# sed -n '1,$'p /etc/grep.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 '1,3'p /etc/grep.txt
rot:x:0:0:/rot:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
2.2.2打印包含某个字母的字符串的行
示例命令如下:
[root@localhost ~]# sed -n '/root/'p /etc/grep.txt
operator:x:11:0:operator:/root:/sbin/nologin
这种用法就类似于grep了,在grep中使用的特殊字符(如^,$,.,*等)同样也可以在sed中使用,如下所示:
[root@localhost ~]# sed -n '/^1/'p /etc/grep.txt
1111111111111111111111111111111
[root@localhost ~]# sed -n '/in$/'p /etc/grep.txt
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
[root@localhost ~]# sed -n '/r..o/'p /etc/grep.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 '/ooo*/'p /etc/grep.txt
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
sed命令加上-e选项可以实现多个行为,如下所示:
[root@localhost ~]# sed -e '1'p -e '/111/'p -n /etc/grep.txt
rot:x:0:0:/rot:/bin/bash
1111111111111111111111111111111
2.2.3删除某些行
示例命令如下:
[root@localhost ~]# sed '1'd /etc/grep.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 /etc/grep.txt
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# sed '/oot/'d /etc/grep.txt
rot:x:0:0:/rot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
这里参数d表示删除的动作,它不仅可以删除指定的单行以及多行,而且可以删除匹配某个字符的行,还可以删除从某一行开始到最后一行所有行。不过,这个操作仅仅是在显示器屏幕上并不显示这些行而已,文档还好好的。
2.2.4替换字符或者字符串
示例命令如下:
[root@localhost ~]# sed '1,2s/ot/to/g' /etc/grep.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
上例中的参数s就表示替换的动作,参数g表示本行全局替换,如果不加g则只替换本行出现的第一个,这个用法其实和vi的替换大同小异。
除了可以使用/作为分隔符外,我们还可以使用其他特殊字符,例如#和@。如下所示:
[root@localhost ~]# sed 's#ot#to#g' /etc/grep.txt
rto:x:0:0:/rto:/bin/bash
operator:x:11:0:operator:/roto:/sbin/nologin
operator:x:11:0:operator:/rooto:/sbin/nologin
roooto:x:0:0:/rooooto:/bin/bash
1111111111111111111111111111111
Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[root@localhost ~]# sed 's@ot@to@g' /etc/grep.txt
rto:x:0:0:/rto:/bin/bash
operator:x:11:0:operator:/roto:/sbin/nologin
operator:x:11:0:operator:/rooto:/sbin/nologin
roooto:x:0:0:/rooooto:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
现在思考一下如何删除文档中的所有的数字或者字母?示例命令如下:
[root@localhost ~]# sed 's/[0-9]//g' /etc/grep.txt
rot:x:::/rot:/bin/bash
operator:x:::operator:/root:/sbin/nologin
operator:x:::operator:/rooot:/sbin/nologin
roooot:x:::/rooooot:/bin/bash
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[0-9]表示任意的数字。这里你也可以提携程[a-zA-Z]或者[0-9a-zA-Z]。如下所示:
[root@localhost ~]# sed 's/[a-zA-Z]//g' /etc/grep.txt
::0:0:/://
::11:0::/://
::11:0::/://
::0:0:/://
1111111111111111111111111111111
2.2.5调换两个字符串的位置
示例命令如下:
[root@localhost ~]# sed 's/\(rot\)\(.*\)\(bash\)/\3\2\1/' /etc/grep.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
小括号在sed中属于特殊符号,必须在前面加转义字符\,替换时间则写成类似\1,\2或\3的形式。上例中用()把想要替换的字符打包成一个整体。有这个转义字符\,会让这个表达式看起来乱糟糟的,有个办法可以省略他。如下所示:
[root@localhost ~]# sed -r 's/(rot)(.*)(bash)/\3\2\1/' /etc/grep.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
没错正如你所看到的,就是这个-r选项让这个表达式更加清晰了。除了调换两个字符串的位置,还常常用sed在某一行前后增加指定内容,如下所示:
[root@localhost ~]# sed 's/^.*$/123&/' /etc/grep.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
2.2.6直接修改文件内容
示例命令如下:
[root@localhost ~]# sed -i 's/ot/to/g' /etc/grep.txt
[root@localhost ~]# cat /etc/grep.txt
rto:x:0:0:/rto:/bin/bash
operator:x:11:0:operator:/roto:/sbin/nologin
operator:x:11:0:operator:/rooto:/sbin/nologin
roooto:x:0:0:/rooooto:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
这样就可以直接更改grep.txt文件中的内容了。但需要注意,在修改前最好先备份文件,以免改错。
2.3awk工具的使用
awk也是流式编辑器,针对文档中的行来操作,一行一行的执行。awk兼具sed的所有功能,而且更加强大。
2.3.1截取文档中的某个段
示例命令如下:
[root@localhost ~]# head -2 /etc/grep.txt |awk -F ':' '{print $1}'
rto
operator
本例中,-F选项的作用是指定分隔符。如果不加-F选项,则以空格或者tab位分隔符。Print为打印的动作,用来打印某个字段。$1为第一个字段,$2为第二个字段,以此类推。但$0比较特殊,他表示整行:
[root@localhost ~]# head -2 /etc/grep.txt |awk -F':' '{print $0}'
rto:x:0:0:/rto:/bin/bash
operator:x:11:0:operator:/roto:/sbin/nologin
注意awk的格式,-F后面紧跟单引号,单引号里面为分隔符,print的动作要用{}括起来,否则会报错。配套还可以打印自定义内容,但是自定义的内容必须用括号括起来。如下所示:
[root@localhost ~]# head -2 /etc/grep.txt |awk -F ':' '{print $1"#"$2"#"$3}'
rto#x#0
operator#x#11
2.3.2匹配字符或者字符串
示例命令如下:
[root@localhost ~]# awk '/oo/' /etc/grep.txt
operator:x:11:0:operator:/rooto:/sbin/nologin
roooto:x:0:0:/rooooto:/bin/bash
这跟sed的用法类似,能实现grep的功能,但没有展示颜色,肯定没有grep用起来方便。不过awk还有比sed更强大的匹配,如下所示:
[root@localhost ~]# awk -F ':' '$1 ~/oo/' /etc/grep.txt
roooto:x:0:0:/rooooto:/bin/bash
他可以让某个段去匹配,这里~就是匹配的意思。awk还可以多次匹配,如下所示:
[root@localhost ~]# awk -F ':' '/root/ {print $1,$3} /test/ {print $1,$3}' /etc/grep.txt
operator 11
本例中awk匹配完root,在匹配test,他可以只打印所匹配的段。
2.3.3条件操作符
示例命令如下:
[root@localhost ~]# awk -F ':' '$3=="0"' /etc/passwd
root:x:0:0:root:/root:/bin/bash
Awk中可以用逻辑符号进行判断,比如==就是等于,也可以理解为精确匹配。另外还有>,>=,<,<=,!=等。值得注意的是,在和数字比较式,若把比较的数字用双引号引起来,那么awk不会认为是数字、会认为是字符,不加双引号则会认为是数字。
[root@localhost ~]# awk -F ':' '$3>=500' /etc/passwd
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
[root@localhost ~]# awk -F ':' '$3>="500"' /etc/passwd
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
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
!=表示不匹配,他除了针对某一个段的字符进行逻辑比较外,还可以在两个段之间进行逻辑比较。如下所示:
[root@localhost ~]# awk -F ':' '$7!="/sbin/nologin"' /etc/passwd
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
[root@localhost ~]# awk -F ':' '$3<$4' /etc/passwd
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 ~]# awk -F ':' '$3>"5" && $3<"7"' /etc/passwd
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
||的用法如下:
[root@localhost ~]# awk -F ':' '$3>1000 || $7=="/bin/bash"' /etc/passwd
root:x:0:0:root:/root:/bin/bash
2.3.4awk的内置变量
awk常用的变量有OFS、NF和NR,OFS和-F选项有类似的功能,也是用来定义分隔符的,但是他在输出的时候定义,NF表示用分隔符的分隔后一共有多少段,NR表示行号。
OFS的用法示例如下:
[root@localhost ~]# head -5 /etc/passwd |awk -F ':' '{OFS="#"} {print $1,3,'4}
root#0#0
bin#1#1
daemon#2#2
adm#3#4
lp#4#7
还有更高级的一些用法:
[root@localhost ~]# awk -F ':' '{OFS="#"} {if ($3>100) {print $1,$2,$3,$4}}' /etc/passwd
systemd-network#x#192#192
polkitd#x#999#998
chrony#x#998#996
变量NF的具体用法如下:
[root@localhost ~]# head -n3 /etc/passwd | awk -F ':' '{print NF}'
7
7
7
[root@localhost ~]# head -n3 /etc/passwd | awk -F ':' '{print $NF}'
/bin/bash
/sbin/nologin
/sbin/nologin
这里NF是多少段,$NF是最后一段的值。NR的具体用法如下:
[root@localhost ~]# head -3 /etc/passwd | awk -F ':' '{print NR}'
1
2
3
我们还可以使用NR作为判断条件,如下所示:
[root@localhost ~]# awk 'NR>10' /etc/passwd
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
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
NR也可以配合段匹配一起是使用,如下所示:
[root@localhost ~]# awk -F ':' 'NR<20 && $1 ~ /root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
2.3.5awk中的数学运算
awk可以更改段值,示例命令如下:
[root@localhost ~]# head -n 3 /etc/passwd |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
awk也可以对各个段的值进行数学运算,示例命令如下:
[root@localhost ~]# head -n2 /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@localhost ~]# head -n2 /etc/passwd |awk -F ':' '{$7=$3+$4;print $0}'
root x 0 0 root /root 0
bin x 1 1 bin /bin 2
awk还可以计算某个段的总和,示例命令如下:
[root@localhost ~]# awk -F ':' '{(tot=tot+$3)}; END {print tot}' /etc/passwd
2605
这里的END是awk特有的语法,表示所有的行都已经执行。其实awk连同sed都可以写成一个脚本文件,而且有他们特有的语法。在awk中使用if判断、for循环都可以,如下所示:
[root@localhost ~]# awk -F ':' '{if ($1=="root") {print $0}}' /etc/passwd
root:x:0:0:root:/root:/bin/bash