七、shell脚本语言文本处理三剑客awk

目录

1、背景:

2、awk工作流程:

3、awk选项: 

4、awk模式 

5、awk操作示例:

示例1:

 示例2:

示例3:

示例4:

示例5:

示例6:

示例7:

示例8:

示例9:

6、内置变量 

示例1:

示例2:

示例3:

示例4:

示例5:

 示例6:

示例7:

 示例8:

7、操作符 

示例1

示例2

示例3

示例4

示例5

示例6

示例7

 示例8

示例9


前一篇: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

后一篇: 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

jiang0615csdn

你对鼓励是我最大的动力来源

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

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

打赏作者

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

抵扣说明:

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

余额充值