目录
前一篇:shell脚本的文本处理sed
1、背景:
awk 是一个处理文本的编程语言工具,能用简短的程序处理标准输入或文件、数据排序、计算以及 生成报表等等。 在 Linux 系统下默认 awk 是 gawk,它是 awk 的 GNU 版本。可以通过命令查看应用的版本:
# ls -l /bin/awk lrwxrwxrwx. 1 root root 4 Nov 26 2020 /bin/awk -> gawk
基本的命令语法:
Usage: awk [POSIX or GNU style options] -f progfile [--] file ... Usage: awk [POSIX or GNU style options] [--] 'program' file ...
awk option 'pattern {action}' file
其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。 花括号用于根据特定的模式对一系列指令进行分组。
awk 处理的工作方式与数据库类似,支持对记录和字段处理,这也是 grep 和 sed 不能实现的。 在 awk 中,缺省的情况下将文本文件中的一行视为一个记录,逐行放到内存中处理,而将一行中的 某一部分作为记录中的一个字段。用 1,2,3...数字的方式顺序的表示行(记录)中的不同字段。用 $后跟数字,引用对应的字段,以逗号分隔,0 表示整个行。
2、awk工作流程:
3、awk选项:
选项 | 作用描述 |
-f program-file | 从文件中读取 awk 程序源文件 |
-F fs | 指定 fs 为输入字段分隔符 |
-v var=value | 变量赋值 |
--posix | 兼容 POSIX 正则表达式 |
--dump-variables=[file] | 把 awk 命令时的全局变量写入文件, 默认文件是 awkvars.out |
--profile=[file] | 格式化 awk 语句到文件,默认是 awkprof.out |
4、awk模式
模式(Pattern) | 作用描述 |
BEGIN{ } | 给程序赋予初始状态,先执行的工作 |
END{ } | 程序结束之后执行的一些扫尾工作 |
/regular expression/ | 为每个输入记录匹配正则表达式 |
pattern && pattern | 逻辑 and,满足两个模式 |
pattern || pattern | 逻辑 or,满足其中一个模式 |
! pattern | 逻辑 not,不满足模式 |
pattern1, pattern2 | 范围模式,匹配所有模式 1 的记录,直到匹配到模式 2 |
awk的动作,就是下面所讲的 print、流程控制、I/O 语句等
5、awk操作示例:
示例1:
从文件读取 awk 程序处理文件
-f -------------------读取awk程序处理文件中的内容
注:没有指定分隔符的时候,默认是采用了空格表示分隔符的
[root@~ test]# cat test.awk
{print $2}
[root@~ test]# tail -n3 /etc/services | awk -f test.awk
48619/tcp
48619/udp
49000/tcp
或
[root@~ test]# tail -n3 /etc/services | awk '{print $2}'
48619/tcp
48619/udp
49000/tcp
示例2:
指定分隔符,打印指定字段
[root@~ test]# awk -F ':' '{print $1}' /etc/passwd
root
bin
daemon
adm
lp
或
[root@~ test]# awk -F":" '{print $1}' /etc/passwd
root
bin
daemon
adm
lp
还可以指定多个分隔符,作为同一个分隔符处理
[]元字符的意思是符号其中任意一个字符,也就是说每遇到一个/或#时就分隔一个字段,当用多个分隔符时,就能更方面处理字段了。
1. 如下的含义就是,取/和#为分隔符,
[root@~ test]# tail -n3 /etc/services
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
matahari 49000/tcp # Matahari Broker
[root@~test]# tail -n3 /etc/services | awk -F"[/#]" '{print $3}'
iqobject
iqobject
Matahari Broker
[root@~test]# tail -n3 /etc/services | awk -F"[/#]" '{print $1}'
iqobject 48619
iqobject 48619
matahari 49000
[root@~test]# tail -n3 /etc/services | awk -F"[/#]" '{print $2}'
tcp
udp
tcp
2. 取空格和/为分隔符,理解就是遇见/或者空格,就进行分隔处理
[root@~test]# tail -n3 /etc/services | awk -F"[ /]+" '{print $1}'
iqobject
iqobject
matahari
[root@~test]# tail -n3 /etc/services | awk -F"[ /]+" '{print $2}'
48619
48619
49000
[root@~test]# tail -n3 /etc/services | awk -F"[ /]+" '{print $3}'
tcp
udp
tcp
[root@~test]# tail -n3 /etc/services | awk -F"[ /]+" '{print $4}'
#
#
#
[root@~test]# tail -n3 /etc/services | awk -F"[ /]+" '{print $5}'
iqobject
iqobject
Matahari
示例3:
awk变量赋值
可以直接在awk中进行变量的赋值,需要使用-v参数引用,
可以直接引用系统变量作为 awk 变量的值,
在输入项中直接使用单引号来赋值变量
[root@~ test]# awk -v a=123 'BEGIN{print a}'
123
[root@~ test]# a=12345
[root@~ test]# awk -v a=$a 'BEGIN{print a}'
12345
[root@~ test]# awk 'BEGIN{print '$a'}'
12345
示例4:
输出 awk 全局变量到文件
--dump-variables=[file] --------把 awk 命令时的全局变量写入文件, 默认文件是 awkvars.out
[root@~ test]# seq 5 | awk --dump-variables '{print $0}'
1
2
3
4
5
[root@~ test]# cat awkvars.out
ARGC: 1
ARGIND: 0
ARGV: array, 1 elements
BINMODE: 0
CONVFMT: "%.6g"
ERRNO: ""
FIELDWIDTHS: ""
FILENAME: "-"
FNR: 5
FPAT: "[^[:space:]]+"
FS: " "
IGNORECASE: 0
LINT: 0
NF: 1
NR: 5
OFMT: "%.6g"
OFS: " "
ORS: "\n"
RLENGTH: 0
RS: "\n"
RSTART: 0
RT: "\n"
SUBSEP: "\034"
TEXTDOMAIN: "messages"
[root@~ test]# ll
total 24
-rw-r--r-- 1 root root 289 Jun 13 17:41 awkvars.out
示例5:
BEGIN 和 END用法,BEGIN 模式是在处理文件之前执行该操作,常用于修改内置变量、变量赋值和打印输出的页眉或标题,END 模式是在程序处理完才会执行。
#打印页眉
[root@~ test]# tail /etc/services | awk 'BEGIN{print "Server\t\tPort\t\t\tDescription\n==="} {print $0}'
Server Port Description
===
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service Protocol
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
matahari 49000/tcp # Matahari Broker
#打印页尾
[root@cnsz92vl17661 test]# tail servers | awk '{print $0}END{print "===\nEND......"}'
nimgtw 48003/udp # Nimbus Gateway
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service Protocol
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
===
END......
示例6:
格式化输出 awk 命令到文件
--profile=[file] -----------------格式化 awk 语句到文件,默认是 awkprof.out
[root@~ test]# tail /etc/services |awk --profile 'BEGIN{print "Service\t\tPort\t\t\tDescription\n==="}{print $0}END{print "===\nEND......"}'
Service Port Description
===
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service Protocol
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
matahari 49000/tcp # Matahari Broker
===
END......
[root@~ test]# cat awkprof.out
# gawk profile, created Mon Jun 13 18:01:22 2022
# BEGIN block(s)
BEGIN {
print "Service\t\tPort\t\t\tDescription\n==="
}
# Rule(s)
{
print $0
}
# END block(s)
END {
print "===\nEND......"
}
示例7:
正则表达式匹配
/regular expression/ -------------------------为每个输入记录匹配正则表达式
匹配包含 tcp 的行
[root@~ test]# tail servers | awk '/tcp/{print $0}'
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service Protocol
isnetserv 48128/tcp # Image Systems Network Services
blp5 48129/tcp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
iqobject 48619/tcp # iqobject
匹配开头是 blp5 的行:
[root@~ test]# tail servers | awk '/^blp5/{print $0}'
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
匹配第一个字段是 8 个字符的行:
[root@~ test]# tail servers | awk '/^[a-z0-9]{8} /{print $0}'
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
示例8:
逻辑 and、or 和 not
pattern && pattern ------------------逻辑 and,满足两个模式
pattern || pattern ------------------逻辑 or,满足其中一个模式
! pattern -----------------------------逻辑 not,不满足模式/regular expression/ -------------------------为每个输入记录匹配正则表达式
匹配记录中包含 blp5 和 tcp 的行:
[root@~ test]# tail servers | awk '/blp5/ && /tcp/{print $0}'
blp5 48129/tcp # Bloomberg locator
匹配记录中包含 blp5 或 tcp 的行:
[root@~ test]# tail servers | awk '/blp5/ || /tcp/{print $0}'
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service Protocol
isnetserv 48128/tcp # Image Systems Network Services
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
iqobject 48619/tcp # iqobject
不匹配开头是#和空行:
[root@~ test]# awk '! /^#/ && ! /^$/{print $0}' /etc/selinux/config
SELINUX=disabled
SELINUX=disabledTYPE=targeted
或
[root@~ test]# awk '! /^#|^$/' /etc/selinux/config
SELINUX=disabled
SELINUX=disabledTYPE=targeted
或
[root@~ test]# awk '/^[^#]|"$"/' /etc/selinux/config
SELINUX=disabled
SELINUX=disabledTYPE=targeted
示例9:
匹配范围
pattern1, pattern2 -------------范围模式,匹配所有模式 1 的记录,直到匹配到模式 2
匹配开头为blp5的到开头为com行的内容
[root@~ test]# tail servers | awk '/^blp5/,/^com/'
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
或
[root@~ test]# awk '/^blp5/,/^com/' servers
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
对匹配范围后记录再次处理,例如匹配关键字下一行到最后一行:
[root@~ test]# seq 5 | awk '/3/,/^$/{printf /3/?"":$0"\n"}'
4
5
另一种判断真假的方式实现:
[root@~ test]# seq 5 | awk '/3/{t=1;next}t'
4
5
1 和 2 都不匹配 3,不执行后面{},执行 t,t 变量还没赋值,为空,空在 awk 中就为假,就不打印 当前行。匹配到 3,执行 t=1,next 跳出,不执行 t。4 也不匹配 3,执行 t,t 的值上次赋值的 1, 为真,打印当前行,以此类推。(非 0 的数字都为真,所以 t 可以写任意非 0 数字) 如果想打印匹配行都最后一行,就可以这样了:
[root@~ test]# seq 5 | awk '/3/{t=1}t'
3
4
5
6、内置变量
变量名 | 作用描述 |
FS | 输入字段分隔符,默认是空格或制表符 |
OFS | 输出字段分隔符,默认是空格 |
RS | 输入记录分隔符,默认是换行符\n |
ORS | 输出记录分隔符,默认是换行符\n |
NF | 统计当前记录中字段个数 |
NR | 统计记录编号,每处理一行记录,编号就会+1 |
FNR | 统计记录编号,每处理一行记录,编号也会+1,与 NR 不同的是,处理第二个 文件时,编号会重新计数。 |
ARGC | 命令行参数数量 |
ARGV | 命令行参数数组序列数组,下标从 0 开始,ARGV[0]是 awk |
ARGIND | 当前正在处理的文件索引值。第一个文件是 1,第二个文件是 2,以此类推 |
ENVIRON | 当前系统的环境变量 |
FILENAME | 输出当前处理的文件名 |
IGNORECASE | 忽略大小写 |
SUBSEP | 数组中下标的分隔符,默认为"\034" |
示例1:
在程序开始前重新赋值 FS 变量,改变默认分隔符为冒号,与-F 的作用是一样的
FS --------------------------------输入字段分隔符,默认是空格或制表符
OFS --------------------------------输出字段分隔符,默认是空格BEGIN{ } ---------------------------给程序赋予初始状态,先执行的工作
[root@ ~]# awk 'BEGIN{FS=":"} {print $1,$2}' /etc/passwd | head -n5
root x
bin x
daemon x
adm x
lp x
或
[root@ ~]# awk -F":" '{print $1,$2}' /etc/passwd | head -n5
root x
bin x
daemon x
adm x
lp x
也可以使用-v 来重新赋值这个变量
[root@~]# awk -v FS=':' '{print $1,$2}' /etc/passwd | head -n5
root x
bin x
daemon x
adm x
lp x
由于 OFS 输出默认以空格分隔,反向引用多个字段分隔的也是空格,如果想指定输出分隔符这样:
[root@~]# awk 'BEGIN{FS=":";OFS=":"} {print $1,$2}' /etc/passwd | head -n5
root:x
bin:x
daemon:x
adm:x
lp:x
[root@~]# awk 'BEGIN{FS=":";OFS="#"} {print $1,$2}' /etc/passwd | head -n5
root#x
bin#x
daemon#x
adm#x
lp#x
或
[root@~]# awk 'BEGIN{FS=":"}{print $1"#"$2}' /etc/passwd |head -n5
root#x
bin#x
daemon#x
adm#x
lp#x
示例2:
RS ---------------------------------------输入记录分隔符,默认是换行符\n
ORS ---------------------------------------输出记录分隔符,默认是换行符\n
RS 默认是\n 分隔每行,如果想指定以某个字符作为分隔符来处理记录:
[root@~]# echo "www.baidu.com/user/test.html" | awk 'BEGIN{RS="/"}{print $0}'
www.baidu.com
user
test.html
RS 也支持正则,sed的n表示读取下一行的内容,a\----表示当前行追加内容
[root@~]# seq -f "str%02g" 10 | sed 'n;n;a\-----' | awk 'BEGIN{RS="-+"}{print $1}'str01
str04
str07
str10
或
[root@~]# seq -f "str%02g" 10 | sed 'n;n;a\-----' | awk 'BEGIN{RS="-----"}{print $1}'
str01
str04
str07
str10
#指定记录分隔符
[root@~]# seq 10 | awk 'BEGIN{ORS="+"} {print $0}'
1+2+3+4+5+6+7+8+9+10+
#指定输入记录分隔符和输出记录分隔符
[root@~]# tail -n2 /test/servers | awk 'BEGIN{RS="/";ORS="#"}{print $0}'
iqobject 48619#tcp # iqobject
iqobject 48619#udp # iqobject
FS、OFS和RS、ORS的作用和含义,这里看起来会有点晕,这个是刚接触确实存在的,通俗的理解就是FS OFS是处理的对象是一行的内容中的字段分隔符,输出来的内容不会做换行处理的,而RS ORS的处理对象是每一行的记录分隔符,输出的内容会默认按照换行进行显示的。
示例3:
NF -------------------------------------统计当前记录中字段个数
#统计字符个数
[root@~]# echo "a b c d e f" | awk '{print NF}'
6
#打印最后一个字段
[root@~]# echo "a b c d e f" | awk '{print $NF}'
f
#打印倒数第二个字段
[root@~]# echo "a b c d e f" | awk '{print $(NF-1)}'
e
#排除最后两个字段
[root@~]# echo "a b c d e f" |awk '{$NF="";$(NF-1)="";print $0}'
a b c d
#排除第一个字段
[root@~]# echo "a b c d e f" |awk '{$1="";print $0}'
b c d e f
示例4:
NR ---------------------------统计记录编号,每处理一行记录,编号就会+1,
FNR -------------------------统计记录编号,每处理一行记录,编号也会+1,与 NR 不同的是,处理第二个 文件时,编号会重新计数。
打印行号
[root@~ test]# tail -n5 servers | awk '{print NR,$0}'
1 blp5 48129/udp # Bloomberg locator
2 com-bardac-dw 48556/tcp # com-bardac-dw
3 com-bardac-dw 48556/udp # com-bardac-dw
4 iqobject 48619/tcp # iqobject
5 iqobject 48619/udp # iqobject
打印总行数
[root@~ test]# tail -n5 servers | awk 'END{print NR}'
5
打印第三行
[root@~ test]# tail -n5 servers | awk 'NR==3'
com-bardac-dw 48556/udp # com-bardac-dw
打印第三行第二个字段
[root@~ test]# tail -n5 servers | awk 'NR==3{print $2}'
48556/udp
打印前三行
[root@~ test]# tail -n5 servers | awk 'NR<=3{print NR,$0}'
1 blp5 48129/udp # Bloomberg locator
2 com-bardac-dw 48556/tcp # com-bardac-dw
3 com-bardac-dw 48556/udp # com-bardac-dw
NR 和 FNR 的区别
[root@~ test]# awk '{print NR,FNR,$0}' a b
1 1 a
2 2 b
3 3 c
4 1 c
5 2 d
6 3 e
[root@~ test]# awk '{print NR,$0}' a b
1 a
2 b
3 c
4 c
5 d
6 e
[root@~ test]# awk '{print FNR,$0}' a b
1 a
2 b
3 c
1 c
2 d
3 e
可以看出 NR 每处理一行就会+1,而 FNR 在处理第二个文件时,编号重新计数。同时也知道 awk 处理 两个文件时,是合并到一起处理。
[root@~ test]# awk 'FNR==NR{print $0"1"}FNR!=NR{print $0"2"}' a b
a1
b1
c1
c2
d2
e2
[root@~ test]# cat a
a
b
c
[root@~ test]# cat b
c
d
e
[root@~ test]#
当 FNR==NR 时,说明在处理第一个文件内容,不等于时说明在处理第二个文件内容。 一般 FNR 在处理多个文件时会用到
示例5:
ARGC ------------------------------是命令行参数数量
ARGV ------------------------------是将命令行参数存到数组,元素由 ARGC 指定,数组下标从 0 开始
[root@~ test]# awk 'BEGIN{print ARGC}' 1 2 3
4
[root@~ test]# awk 'BEGIN{print ARGV[0]}'
awk
[root@~ test]# awk 'BEGIN{print ARGV[1]}' 1 2
1
[root@~ test]# awk 'BEGIN{print ARGV[2]}' 1 2
2
示例6:
ARGIND ----------------是当前正在处理的文件索引值,第一个文件是 1,第二个文件是 2,以此类推,从而可以通 过这种方式判断正在处理哪个文件
[root@~ test]# awk '{print ARGIND,$0}' a b
1 a
1 b
1 c
2 c
2 d
2 e
[root@~ test]# awk 'ARGIND==1{print "a->"$0}ARGIND==2{print "b->"$0}' a b
a->a
a->b
a->c
b->c
b->d
b->e
[root@~ test]# awk 'ARGIND==1 {print $1}' a b
a
b
c
[root@~ test]# awk 'ARGIND==2 {print $1}' a b
c
d
e
示例7:
ENVIRON ------------------------------------------调用系统变量
[root@~ test]# awk 'BEGIN{print ENVIRON["HOME"]}'
/root
[root@~ test]# awk 'BEGIN{print ENVIRON["a"]}'
[root@~ test]# a=123456
[root@~ test]# awk 'BEGIN{print ENVIRON["a"]}'
[root@~ test]# export a
[root@~ test]# awk 'BEGIN{print ENVIRON["a"]}'
123456
示例8:
FILENAME -------------------是当前处理文件的文件名
NR ----------------------------统计记录编号,每处理一行记录,编号就会+1
FNR -------------------------不同的是在统计第二个文件时会重新计
[root@~ test]# cat a
a
b
c
[root@~ test]# cat b
c
d
e
[root@~ test]# awk 'FNR==NR{print FILENAME"->"$0}FNR!=NR{print FILENAME"->"$0}' a b
a->a
a->b
a->c
b->c
b->d
b->e
[root@~ test]# echo "A a b c" |xargs -n1 |awk 'BEGIN{IGNORECASE=1}/a/'
A
a
IGNORECASE等于 1 代表忽略大小写。
7、操作符
运算符 | 功能描述 |
(....) | 分组 |
$ | 字段引用 |
++ -- | 递增和递减 |
+ - ! | 加号,减号,和逻辑否定 |
* / % | 乘,除和取余 |
+ - | 加法,减法 |
| |& | 管道,用于 getline,print 和 printf |
< > <= >= != == | 关系运算符 |
~ !~ | 正则表达式匹配,否定正则表达式匹配 |
in | 数组成员 |
&& || | 逻辑 and,逻辑 or |
?: | 简写条件表达式: expr1 ? expr2 : expr3 第一个表达式为真,执行 expr2,否则执行 expr3 |
= += -= *= /= %= ^= | 变量赋值运算符 |
注:
在 awk 中,有 3 种情况表达式为假:数字是 0,空字符串和未定义的值。
数值运算,未定义变量初始值为 0。
字符运算,未定义变量初始值为空。
数据运算,初始值为0 [root@~ test]# awk 'BEGIN{n=0;if(n)print "true";else print "false"}' false 字符运算,赋值为空 [root@~ test]# awk 'BEGIN{s="";if(s)print "true";else print "false"}' false 未定义变量值 [root@~ test]# awk 'BEGIN{if(s)print "true";else print "false"}' false
示例1
通过awk截取一段整数
[root@~ test]# echo "123abc abc123 123abc123" |xargs -n1 | awk '{print +$0}'
123
0
123
[root@~ test]# echo "123abc abc123 123abc123" |xargs -n1 | awk '{print -$0}'
-123
0
-123
示例2
感叹号用法
[root@~ test]# seq 6 |awk 'i=!i'
1
3
5
[root@~ test]# seq 6 |awk '!(i=!i)'
2
4
6
过程解析:
读取第一行:i 是未定义变量,也就是 i=!0,!取反意思。
感叹号右边是个布尔值,0 或空字符串为假,但是非 0 或非空字符串为真,那么!0 就是真,当前的 i=1,条件为真打印当前记录。
注:没有 print 为什么会打印呢?因为模式后面没有动作,默认会打印整条记录。
读取第二行:因为上次 i 的值由 0 变成了 1,此时就是 i=!1,1表示为真,但是取反就成了假的,那么就不用打印,当前的1=2的。
读取第三行:因为上次 i 的值由 1变成了 0,此时就是 i=!0,0表示为假,但是取反就成了真,那么就需要用打印,当前的1=3的
读取第四行:因为上次 i 的值由 0变成了 1,此时就是 i=!1,1表示为真,但是取反就成了假,那么就不用打印,当前的1=4的
读取第五行:因为上次 i 的值由 1变成了 0,此时就是 i=!0,0表示为假,但是取反就成了真,那么就需要用打印,当前的1=5的
读取第六行:因为上次 i 的值由 0变成了 1,此时就是 i=!1,1表示为真,但是取反就成了假,那么就不用打印,当前的1=4的。
那么去偶数的思路就是在取奇数的基础上再次取反就可以了。
示例3
不匹配某行,就是反向的思维,在取指定行的内容中取反即可
[root@~ test]# tail servers | awk '!/blp5/{print $0}'
nimgtw 48003/udp # Nimbus Gateway
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service Protocol
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
示例4
awk的乘法和除法使用
[root@~ test]# seq 5 |awk '{print $0*2}'
2
4
6
8
10
[root@~ test]# seq 5 |awk '{print $0%2}'
1
0
1
0
1
取值偶数
[root@cnsz92vl17661 test]# seq 5 |awk '$0%2==0{print $0}'
2
4
[root@cnsz92vl17661 test]# seq 5 |awk '$0%2!=1{print $0}'
2
4
取值奇数
[root@cnsz92vl17661 test]# seq 5 |awk '$0%2==1{print $0}'
1
3
5
[root@cnsz92vl17661 test]# seq 5 |awk '$0%2!=0{print $0}'
1
3
5
$0是表示每一行的内容,除法的使用,是能被整除的则打印出0,不能被整除的表示为1
示例5
awk的 | 管道符使用
[root@~ test]# seq 5 | shuf | awk '{print $0|"sort"}'
1
2
3
4
5
shuf表示将顺序打乱,每次执行的顺序都是不一样的,sort是正向排序
示例6
awk使用正则表达式匹配
[root@~ test]# seq 5 | awk '$0~3{print $0}'
3
[root@~ test]# seq 5 | awk '$0!~3{print $0}'
1
2
4
5
[root@~ test]# seq 5 | awk '$0~/[34]/{print $0}'
3
4
[root@~ test]# seq 5 | awk '$0!~/[34]/{print $0}'
1
2
5
[root@~ test]# seq 5 | awk '$0~/[^34]/{print $0}'
1
2
5
~的含义是匹配到的内容,~3就是匹配3的内容[34]表示取值在括号里的内容
示例7
awk用作判断数组成员
[root@~ test]# awk 'BEGIN{a["a"]=123}END{if("a" in a)print "yes"}' </dev/null
yes
示例8
三目运算符
[root@~ test]# awk 'BEGIN{print 1==1?"yes":"no"}'
yes
[root@~ test]# awk 'BEGIN{print 1==2?"yes":"no"}'
no
[root@~ test]# seq 3 | awk '{print $0==2?"yes":"no"}'
no
yes
no
替换换行符为逗号:
[root@~ test]# seq 5 |awk '{print n=(n?n","$0:$0)}'
1
1,2
1,2,3
1,2,3,4
1,2,3,4,5
[root@~ test]# seq 5 |awk '{n=(n?n","$0:$0)}END{print n}'
1,2,3,4,5
说明:读取第一行时,n 没有变量,为假输出$0 也就是 1,并赋值变量 n,读取第二行时,n 是 1 为 真,输出 1,2 以此类推,后面会一直为真。
每三行加入一行的内容
[root@~ test]# seq 10 |awk '{print NR%3?$0:$0 "\ntxt"}'
1
2
3
txt
4
5
6
txt
7
8
9
txt
10‘’
两行合并一行:
[root@~ test]# seq 6 |awk '{printf NR%2!=0?$0" ":$0" \n"}'
1 2
3 4
5 6
[root@~ test]# seq 6 |awk 'ORS=NR%2?" ":"\n"'
1 2
3 4
5 6
[root@cnsz92vl17661 test]# seq 6 |awk '{if(NR%2)ORS=" ";else ORS="\n";print}'
1 2
3 4
5 6
示例9
变量赋值
[root@~ test]# seq 5 |awk '{sum+=1}END{print sum}'
5
[root@~ test]# seq 5 |awk '{sum+=$0}END{print sum}'
15
sum+1和sum+$0是有区别的,第一个是+1,连接加5次,过程如下:
0+1
1+1
2+1
3+1
4+1
第二是打印的数组全部相加一次
0+1
1+2
3+3
6+4
10+5
后一篇: