【LinuxShell】Shell编程之sed与awk


一、sed编辑器

1.sed编辑器概念

  sed是一种流编辑器,流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。

  sed编辑器可以根据命令来处理数据流中的数据,这些命令要么从命令行中输入,要么存储一个命令文本文件中。

2.sed编辑器工作流程

  sed 的工作流程主要包括读取执行显示三个过程:

    读取:sed从输入流(文件、管道、标准输入〉中读取一行内容并存储到临时的缓冲区中(又称模式空间,pattern space)。
    执行:默认情况下,所有的sed命令都在模式空间中顺序地执行,除非指定了行的地址,否则临时sed命令将会在所有的行上依次执行
    显示:发送修改后的内容到输出流。在发送数据后,模式空间将会被清空

  在所有的文件内容都被处理完成之前,上述过程将重复执行,直至所有内容被处理完。

  注意:默认情况下所有的sed命令都是在模式空间内执行的,因此输入的文件并不会发生任何变化,除非是用重定向存储输出。

处理大文件较卡问题

  流编辑器处理大文件比较卡可以使用两种方式来处理。sped命令将大文件分成若干个小文件读取。或者使用cat命令读取全部文件放在临时缓冲区中,然后交给流编辑器(grep、sed、awk)进行处理,由于使用car命令时IO消耗比较低。

3.sed编辑器用法

命令格式

sed -e '操作' 文件l 文件2 ...
sed -n -e '操作' 文件1 文件2 ...
sed -f 脚本文件 文件1 文件2 ...
sed -i -e '操作' 文件1 文件2 ...

sed -e 'n{				#n意为:指定行
操作l
操作2
...
}' 文件1 文件2 ...

常用选项

选项含义
-e--expression=表示用指定命令来处理输入的文本文件,只有一个操作命令时可省略,一般在执行多个操作命令使用。
-f--file=表示用指定的脚本文件来处理输入的文本文件。
-h--help显示帮助。
-n--quietsilent禁止sed编辑器输出,但可以与p命令一起使用完成输出。
-i直接修改目标文本文件。

常用操作

操作含义
s替换,替换指定字符。
d删除,删除选定的行。
a增加,在当前行下面增加一行指定内容。
i插入,在选定行上面插入一行指定内容。
c替换,将选定行替换为指定内容。
y字符转换,转换前后的字符长度必须相同。
p打印,如果同时指定行,表示打印指定行;如果不指定行,则表示打印所有内容,如果有非打印字符,则以ASCII码输出。其通常与-n选项一起使用。
=打印行号。
l(小写L)打印数据流中的文本和不可打印的AscII字符(比如结束符$、制表符\t)

常用方式

打印内容
[root@localhost ~]# sed -n -e 'p' testfile1			#打印内容

[root@localhost ~]# sed -n -e '=' testfile1			#打印行号

[root@localhost ~]# sed -n -e 'l' testfile1			#打印隐藏特殊符号

[root@localhost ~]# sed -n -e '=;p' testfile1		#打印行号和内容
[root@localhost ~]# sed -n -e '=' -e 'p'testfile1	#打印行号和内容

sed编辑器的寻址方式

  • 以数字形式表示行区间
  • 用文本模式来过滤出行
[root@localhost ~]# sed -n '1p' testfile1					#打印第1行

[root@localhost ~]# sed -n '$p' testfile1					#打印最后一行

[root@localhost ~]# sed -n '1,3p' testfile1					#打印1到3行

[root@localhost ~]# sed -n '3,$p' testfile1					#从第3行开始打印,直到最后一行结束

[root@localhost ~]# sed -n '1,+3p' testfile1				#打印第1行之后的连续3行,即1-4行

[root@localhost ~]# sed '5q' testfile1						#打印前5行信息后退出,q表示退出

[root@localhost ~]# sed -n 'p;n' testfile1					#打印奇数行,n表示移动到下一行
[root@localhost ~]# sed -n '3{p;n;n;p}' testfile1			#打印第3,5行

[root@localhost ~]# sed -n 'n;p' testfile1					#打印偶数行
	
[root@localhost ~]# sed -n '2,${n;p}' testfile1				#从第2行开始,从下一行开始打印,即第3、5、7行

[root@localhost ~]# sed -n '/user/p' /etc/passwd			#打印包含user的行

[root@localhost ~]# sed -n '/^a/p' /etc/passwd				#打印以a开头的行

[root@localhost ~]# sed -n '/bath$/p' t/etc/passwd			#打印以bath结尾的行

[root@localhost ~]# sed -n '/ftp\|root/p' /etc/passwd		#打印含有ftp或者root的行
[root@localhost ~]# sed -nr '/ftp|root/p' /etc/passwd		#-r表示支持扩展正则表达式

[root@localhost ~]# sed -n '2,/nobody/p' /etc/passwd		#打印从第2行开始,直到第一个包含nobody的行结束

[root@localhost ~]# sed -n '2,/nobody/=' /etc/passwd		#打印从第2行开始,直到第一个包含nobody的行结束的行号

[root@localhost ~]# sed -nr '/ro{1,}t/p' /etc/passwd		#打印包含root的行,root中o的个数可以是1个以上
删除行内容
[root@localhost ~]# sed 'd' testfile1						#全删

[root@localhost ~]# sed '3d' testfile1						#删除第3行

[root@localhost ~]# sed '2,4d' testfile1					#删除第2到4行

[root@localhost ~]# sed '$d' testfile1						#删除最后一行

[root@localhost ~]# sed '/^$/d' testfile1					#删除空行

[root@localhost ~]# sed '/nologin$/d' /etc/passwd			#删除以nologin结尾的文件

[root@localhost ~]# sed '/nologin$/!d' /etc/passwd			#"!"表示取反

[root@localhost ~]# sed '/2\|3/d' testfile2					#删除第2行和第3行
[root@localhost ~]# sed '/2/,/3/d' testfile2				#从第一个位置打开行删除功能,到第二个位置关闭行删除功能
[root@localhost ~]# sed '/1/,/3/d' testfile2				#从第一个包含1的行打开删除功能,到第一个包含3的行关闭删除功能,然后接着往下扫描重复之前操作,若包含3的行不存在,则一删到底。
替换内容

命令格式

行范围 s/旧字符/新字符串/替换标记

替换标记

数字表明新字符串将替换第几处匹配的地方
g表明新字符串将会替换所有匹配的地方
p打印与替换命令匹配的行,与-n一起使用
w 文件将替换的结果写到文件中

使用方式

[root@localhost ~]# sed -n 's/root/admin/p' /etc/passwd					#将匹配行中第一个root替换为admin然后打印替换的行
	
[root@localhost ~]# sed -n 's/root/admin/2p' /etc/passwd				#将匹配行中第二个root替换为admin然后打印替换的行

[root@localhost ~]# sed -n 's/root/admin/gp' /etc/passwd				#将匹配行所有root替换为admin然后打印替换的行
[root@localhost ~]# sed -n 's/root/admin/gw file' /etc/passwd			#将匹配行所有root替换为admin然后保存替换的行至file
[root@localhost ~]# sed -n 's/root/admin/gp' /etc/passwd > file			#将匹配行所有root替换为admin然后保存替换的行至file

[root@localhost ~]# sed 's/root//g' /etc/passwd							#将匹配行所有root替换为空的

[root@localhost ~]# sed 'l,20 s/^/#/' /etc/passwd						#在第1到20行进行注释
[root@localhost ~]# sed '/^root/ s/$/#/' /etc/passwd					#将以root开头的行进行注释

[root@localhost ~]# sed '/root/ s/^/#/' /etc/passwd						#将包含root的行进行注释
[root@localhost ~]# sed -rn 's /.*root.*/#&/p' /etc/passwd				#用正则匹配行内容,然后通过&获取前面匹配的内容进行注释后打印

[root@localhost ~]# sed -f script.sed testfile2							#对某个文件执行指定命令文件

[root@localhost ~]# sed '1,20w out.txt' /etc/passwd
[root@localhost ~]# sed '1,20 s/^/#/w out.txt' /etc/passwd				#将文件的第1到20行进行注释,然后将修改的行内容保存至指定文件

[root@localhost ~]# sed -n 's/\/bin\/bash/\/bin\/csh/p' /etc/passwd		#将文件中/bin/bash替换为/bin/csh,然后打印替换的行
[root@localhost ~]# sed -n 's!/bin\/bash!/bin\/csh!p' /etc/passwd		#使用"!"作为字符串分隔符,可以使用除了斜杠的其他字符
[root@localhost ~]# sed -i 's9\945\9\99\98\939' /etc/passwd				#将94599替换为9893
插入内容

基本使用

[root@localhost ~]# sed '/45/c ABC' testfile2							#将含有45的行都替换为ABC

[root@localhost ~]# sed 'y/145/ABC/' testfile2							#使所有的1字符转换成a,所有的2字符转换成B,所有的3字符转换成c

[root@localhost ~]# sed 'l,3a ABC' testfile2							#在第1行到第3行后都插入ABC新的一行

[root@localhost ~]# ed 'li ABC' testfile2								#在第一行前插入ABC新的一行

[root@localhost ~]# sed '5r /etc/resolv.conf' testfile2					#在第5行读取/etc/resolv.conf文件

保持空间的使用

[root@localhost ~]# sed '/root/{H;d};$G’ /etc/passwd					#将包含root的行剪切到末尾,H表示复制到剪切板,G表示粘贴到指定行后

[root@localhost ~]# sed '1,2H;3,4G' /etc/passwd						#将1、2行复制到3和4行的下面

高级使用(sed分组概念)

[root@localhost ~]# echo "111222333" | sed -r 's/(111)(222)/\2\1/'		#将字符111和 222互换位置
[root@localhost ~]# echo "111222333" | sed -r 's/^(.)(.*)(.)$/\3\2\1/'	#将第一个字符和最后一个字符互换

二.awk编辑器

1.概念

  sed命令常用于一整行的处理,而awk比较倾向于将一行分成多个"字段"然后再进行处理。awk信息的读入也是逐行读取的,执行结果可以通过print的功能将字段数据打印显示。

  在使用awk命令的过程中,可以使用逻辑操作符 &&表示与、||表示或、!表示非;还可以进行简单的数学运算,如+-*/%^分别表示加、减、乘、除、取余和乘方。

2.工作原理

  逐行读取文本,默认以空格或tab键为分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令。

3.用法

命令格式

awk 选项 '模式或条件 {操作}' 文件1 文件2 ...
awk -f 脚本文件 文件l 文件2 ...

常见的内建变量

内建变量含义
FS列分割符。指定每行文本的字段分隔符,默认为空格或制表位。与-F作用相同。
NF当前处理的行的字段个数。$NF代表最后一个字段。
NR当前处理的行的行号(序数)。
$0当前处理的行的整行内容。
$n当前处理行的第n个字段(第n列)。
FILENAME被处理的文件名。
RS行分隔符。awk从文件上读取资料时,将根据Rs的定义把资料切割成许多条记录,而awk比较倾向于将一行分成多个一次仅读入一条记录,以进行处理。预设值是\n

常用方式

按行输出文本

输出所有内容

[root@localhost opt]# awk '{print}' testfile1 
one
two
three
four
five
six
seven
eight
nine
ten
eleven
twelve
[root@localhost opt]# awk '{print $0}' testfile1 
one
two
three
four
five
six
seven
eight
nine
ten
eleven
twelve

输出指定行内容

###输出第1行内容
[root@localhost opt]# awk 'NR==1 {print}' testfile1 
one

###输出第3行内容
[root@localhost opt]# awk 'NR==3 {print}' testfile1 
three

###输出第1~3行内容
[root@localhost opt]# awk 'NR==1,NR==3 {print}' testfile1 
one
two
three
[root@localhost opt]# awk '(NR>=1)&&(NR<=3){print}' testfile1
one
two
three

###输出第1行、第3行的内容
[root@localhost opt]# awk 'NR==1||NR==3 {print}' testfile1 
one
three

输出奇偶数行的内容

###输出偶数行的内容
[root@localhost opt]# awk '(NR%2)==0{print}' testfile1 
two
four
six
eight
ten
twelve

###输出奇数行的内容
[root@localhost opt]# awk '(NR%2)==1{print}' testfile1 
one
three
five
seven
nine
eleven

输出含有字符串的行

###输出含有root的行
[root@localhost opt]# awk '/root/{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

###输出以root开头的行
[root@localhost opt]# awk '/^root/{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

###输出以nologin结尾的行
[root@localhost opt]# awk '/nologin$/{print}' /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
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
...
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin

统计以/bin/bash 结尾的行数

[root@localhost opt]# awk 'BEGIN {x=0};/\/bin\/bash$/{x++};END {print x}' /etc/passwd
2

此命令等同于grep -c "/bin/bash$" /etc/passwd

BEGIN模式表示,在处理指定的文本之前,需要先执行BEGIN模式中指定的动作;awk再处理指定的文本,之后再执行END模式中指定的动作,END{}语句块中,往往会放入打印结果等语句。

按字段输出文本

输出每行中(以控股或制表位分隔)的第3个字段

[root@localhost opt]# awk -F":" '{print $3}' /etc/passwd
0
1
2
3
4
5
6
...
38
42
29
65534
98
74
70
89
72
1000

输出每行中的第1、3个字段

[root@localhost opt]# awk -F":" '{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
...
geoclue 989
ntp 38
gdm 42
rpcuser 29
nfsnobody 65534
gnome-initial-setup 988
sshd 74
avahi 70
postfix 89
tcpdump 72
tang 1000

输出特定条件的行的字段内容

###输出第3个字段的值小于5的第1、3个字段内容
[root@localhost opt]# awk -F":" '$3<5{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4

###输出第3个字段不小于200的行
[root@localhost opt]# awk -F":" '!($3<200){print $1,$3}' /etc/passwd
polkitd 999
libstoragemgmt 998
colord 997
saned 996
gluster 995
saslauth 994
setroubleshoot 993
chrony 992
unbound 991
sssd 990
geoclue 989
nfsnobody 65534
gnome-initial-setup 988
tang 1000

###输出第3个字段大于等于1000的行,用if语句进行判断
[root@localhost opt]# awk 'BEGIN{FS=":"};{if($3>=1000){print}}' /etc/passwd
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
tang:x:1000:1000:tang:/home/tang:/bin/bash

使用三元运算符输出内容

如果第3个字段的值大于等于第4个字段的值,则把第3个字段的值赋给max,否则第4个字段的值赋给max

[root@localhost opt]# awk -F":" '{max=($3>=$4)?$3:$4;{print max}}' /etc/passwd
0
1
2
4
7
5
6
7
12
11
100
50
99
192
81
999
998
997
32
996
995
994
173
993
172
171
75
992
991
107
59
990
113
989
38
42
29
65534
988
74
70
89
72
1000

输出每行内容和行号

每处理完一条记录,NR值加1

[root@localhost opt]# awk -F":" '{print NR,$0}' /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 libstoragemgmt:x:998:995:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
18 colord:x:997:994:User for colord:/var/lib/colord:/sbin/nologin
19 rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
20 saned:x:996:993:SANE scanner daemon user:/usr/share/sane:/sbin/nologin
21 gluster:x:995:992:GlusterFS daemons:/run/gluster:/sbin/nologin
22 saslauth:x:994:76:Saslauthd user:/run/saslauthd:/sbin/nologin
23 abrt:x:173:173::/etc/abrt:/sbin/nologin
24 setroubleshoot:x:993:990::/var/lib/setroubleshoot:/sbin/nologin
25 rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin
26 pulse:x:171:171:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
27 radvd:x:75:75:radvd user:/:/sbin/nologin
28 chrony:x:992:987::/var/lib/chrony:/sbin/nologin
29 unbound:x:991:986:Unbound DNS resolver:/etc/unbound:/sbin/nologin
30 qemu:x:107:107:qemu user:/:/sbin/nologin
31 tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
32 sssd:x:990:984:User for sssd:/:/sbin/nologin
33 usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin
34 geoclue:x:989:983:User for geoclue:/var/lib/geoclue:/sbin/nologin
35 ntp:x:38:38::/etc/ntp:/sbin/nologin
36 gdm:x:42:42::/var/lib/gdm:/sbin/nologin
37 rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
38 nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
39 gnome-initial-setup:x:988:982::/run/gnome-initial-setup/:/sbin/nologin
40 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
41 avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
42 postfix:x:89:89::/var/spool/postfix:/sbin/nologin
43 tcpdump:x:72:72::/:/sbin/nologin
44 tang:x:1000:1000:tang:/home/tang:/bin/bash

输出两种指定条件的内容

###输出以冒号分隔且第7个字段中包含/bash的行的全部内容
[root@localhost opt]# awk -F":" '$7~"/bash"{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
tang:x:1000:1000:tang:/home/tang:/bin/bash

###输出以冒号分隔且第7个字段中包含/bash的行的第1个字段
[root@localhost opt]# awk -F":" '$7~"/bash"{print $1}' /etc/passwd
root
tang

###输出第1个字段中包含root且有7个字段的行的第1、2个字段
[root@localhost opt]# awk -F":" '($1~"root")&&(NF==7){print $1,$2}' /etc/passwd
root x

###输出第7个字段既不为/bin/bash,也不为/sbin/nologin的所有行
[root@localhost opt]# awk -F":" '($7!="/bin/bash")&&($7!="/sbin/nologin"){print}' /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
通过管道、双引号调用 Shell命令

统计以冒号分隔的文本段落数,END{}语句块中,往往会放入打印结果等语句。

每处理完一条记录,NR值加1

[root@localhost opt]# echo $PATH | awk 'BEGIN {RS=":"}; END{print NR}'
5

调用wc -l命令统计使用bash 的用户个数

[root@localhost opt]# awk -F: '/bash$/{print | "wc -l"}' /etc/passwd
2
[root@localhost opt]# awk -F: '/bash$/{print}' /etc/passwd | wc -l
2

此命令等同于grep -c "bash$" /etc/passwd

查看当前内存使用百分比

[root@localhost opt]# free -m | awk '/Mem:/ {print int($3/($3+$4)*100)"%"}'
33%
[root@localhost opt]# free -m | awk '/Mem:/ {print $3/$2 * 100"%"}'
24.1379%

查看当前CPU空闲率

[root@localhost opt]# top -b -n 1 | awk -F"," '/%Cpu/ {print $4}' | awk '{print $1}'
100.0
[root@localhost opt]# top -b -n 1 | grep Cpu | awk -F ',' '{print $4}' | awk '{print $1}'
100.0

-b -n 1表示只需要1次的输出结果。

查看当前磁盘的情况

###查看当前磁盘的使用率
[root@localhost opt]# df | awk '$NF=="/" {print $5}'
13%
###查看当前磁盘的空闲率
[root@localhost opt]# df | awk '$NF=="/" {print $5}' | awk -F% '{print 100-$1"%"}'
87%

显示上次系统重启时间

[root@localhost opt]# date -d "$(awk -F "." '{print $1}' /proc/uptime) second ago" +"%F %H:%M:%S"
2023-05-15 08:44:02
[root@localhost opt]# date -d "$(cat /proc/uptime | awk -F. '{print $1} ' ) second ago" +"%Y-%m-%d %H:%M:%S"
2023-05-15 08:44:02

常见日期用法

###当月第一天
[root@localhost opt]# date +%Y%m01
20230501

##下个月第一天
[root@localhost opt]# date -d "1 month" +%Y%m01
20230601

###上个月第一天
[root@localhost opt]# date -d "-1 month" +%Y%m01
20230401
[root@localhost opt]# date -d "1 month ago" +%Y%m01
20230401

###明天
[root@localhost opt]# date -d "1 day" +%Y%m%d
20230516

##昨天
[root@localhost opt]# date -d "-1 day" +%Y%m%d
20230514
[root@localhost opt]# date -d "yesterday" +"%Y%m%d" 
20230514

###上个月最后一天
[root@localhost opt]# date -d "$(date +%Y%m01) -1 day" +%Y%m%d
20230430

###当月最后一天
[root@localhost opt]# date -d "$(date -d "1 month" +%Y%m01) -1 day" +%Y%m%d
20230531

面试题:每个月最后一天去执行指定文件

方式1:脚本中进行判断
###当月最后一天
lastday=$(date -d "$(date -d "1 month" + "%Y%m01") -1 day" +"%Y%m%d")
###今天
today=$(date +%Y%m%d)
###判断今天是否是最后一天
if [ "$today" == "$lastday" ];then 执行文件

方式2:计划性任务中判断
0 0 28-31 if [ "$(date -d "$(date -d "1 month" + "%Y%m01") -1 day" +"%Y%m%d")" == "today=$(date +%Y%m%d)"];then 执行文件

调用w命令,并用来统计在线用户数

[root@localhost opt]# awk 'BEGIN{n=0;while("w" | getline) n++ ;{print n-2}}'
2

调用hostname,并输出当前的主机名

[root@localhost opt]# awk 'BEGIN{"hostname" | getline ;{print $0}}'
localhost.localdomain

获取奇偶数行

###获取偶数行
[root@localhost opt]# seq 10 | awk '{getline;print $0}'
2
4
6
8
10

###获取奇数行
[root@localhost opt]# seq 10 | awk '{print $0;getline}'
1
3
5
7
9

getline左右无重定向符<|时,awk首先读取到了第一行,就是1,然后使用getline就得到了1下面的第二行,就是2,因为getline之后,awk会改变对应的NFNRFNR$0等内部变量,所以此时的$0的值就不再是1,而是2了,然后将它打印出来。

getline左右有重定向符<|时,getline则作用于定向输入文件,由于该文件是刚打开,并没有被awk读入一行,只是getline读入,那么getline返回的是该文件的第一行,而不是隔行。

查看使用特定分隔符的字符串

###输出A B C D字符串
[root@localhost opt]# echo "A B C D"
A B C D

###输出ABCD字符串以及用|分隔的字符串
[root@localhost opt]# echo "A B C D" | awk '{OFS="|";print $0;$1=$1;print $0}'
A B C D
A|B|C|D

###输出以逗号分隔的ABCD字符串
[root@localhost opt]# echo "A B C D" | awk 'BEGIN{OFS=","};{$2=$2;print $0}'
A,B,C,D
echo "A B C D" | awk '{print $1","$2","$3","$4}'
A,B,C,D

OFS是列输出分隔符,可以用来指定分隔符。

$1=$1是用来激活$0的重新赋值,也就是说字段$1…和字段数NF的改变会促使awk重新计算$0的值,通常是在改变OFS后而需要输出$0时这样做。

按数组输出文本以及统计

下标是数字时输出文本

[root@localhost opt]# awk 'BEGIN{a[0]=10;a[1]=20;print a[1]}'
20
[root@localhost opt]# awk 'BEGIN{a[0]=10;a[1]=20;print a[0]}'
10

下标是一串字符时输出文本

[root@localhost opt]# awk 'BEGIN{a["abc"]=10;a["xyz"]=20;print a["abc"]}'
10
[root@localhost opt]# awk 'BEGIN{a["abc"]=10;a["xyz"]=20;print a["xyz"]}'
20

其中字符串需要用双引号包起来。

下标是数字,使用循环输出文本

[root@localhost opt]# awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30;for(i in a){print a[1]}}'
20
20
20
[root@localhost opt]# awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30;for(i in a){print a[2]}}'
30
30
30

其中BEGIN中的命令只执行一次

通过数组统计重复行的数量

[root@localhost opt]# cat test.txt
aaa
aaa
bbb
ccc
aaa
bbb
aaa
###统计重复字符串的数量以及输出对应的字符串
[root@localhost opt]# awk '{a[$1]++}END{for(i in a){print a[i],i}}' test.txt 
4 aaa
1 ccc
2 bbb
###从大到小排序
[root@localhost opt]# awk '{a[$1]++}END{for(i in a){print a[i],i}}' test.txt |sort -r
4 aaa
2 bbb
1 ccc

a[1]初始为0,a[1]++后即为1,而这里awk中的a[1]++最终的值是由test.txt文本内容有多少行决定的,文本逐行读取完毕后再执行END中的命令。

统计登录失败的ip地址出现的次数

[root@localhost log]# cat /var/log/secure | awk '/Failed password/{print $11}' | sort -n |uniq -c
      3 192.168.145.30
      1 192.168.145.45

[root@localhost log]# cat /var/log/secure | awk '/Failed password/{a[$11]++}; END{for(i in a){print a[i],i}}'
1 192.168.145.45
3 192.168.145.30
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我的宝贝大唐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值