正则表达式

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

相关推荐
吴声子夜歌11 小时前
Shell编程实例——编写安全的shell脚本(二)
linux·运维·shell
zx_7414848113 小时前
【Linux入门】Shell 函数、正则表达式与文本处理:cut 与 awk
linux·运维·正则表达式
吴声子夜歌2 天前
Shell编程实例——内务及管理任务(一)
linux·运维·shell
吴声子夜歌2 天前
Shell编程实例——高级脚本编程(一)
linux·运维·网络·shell
吴声子夜歌2 天前
Shell编程实例——bash的配置与自定义(二)
linux·运维·shell
吴声子夜歌3 天前
Shell编程实例——与解析相关的任务(二)
linux·运维·shell
吴声子夜歌3 天前
Shell编程实例——脚本编程的附加特性
linux·运维·shell
云计算练习生3 天前
什么是内核?操作系统内核到底管哪些事
linux·windows·操作系统·内核·shell
Patrick在香港3 天前
Claude Prompt 香港场景:公文里「今日」落在 6 个日历日上,「翌日」锚错了 5 天
python·自然语言处理·正则表达式·claude·数据清洗
梦帮科技5 天前
Next.js 16 模块化单体实战:App Router、领域模块与 Route Handler 分层
css·数据结构·链表·正则表达式·node.js·json·html5