awk 整理
1. 概念
awk是一种专门为文本处理设计的编程语言,它是Linux和Unix环境中功能强大的数据处理引擎之一。awk的名称来源于其创始人阿尔佛雷德·艾侯(Alfred Aho)、彼得·温伯格(Peter Weinberger)和布莱恩·柯林汉(Brian Kernighan)姓氏的首个字母。
awk的工作原理是逐行读取文本,默认以空格或Tab键为分隔符进行分隔,将分隔所得的各个字段保存到内置变量中,并按模式或条件执行编辑命令。awk提供了强大的功能,包括样式装入、流控制、数学运算、进程控制语句以及内置的变量和函数。
awk的语法格式基本为“awk 选项 ‘模式或条件 {操作}’ 文件1 文件2”,还可以使用脚本文件或命令行参数来执行。awk中常用的内置变量包括FS(字段分隔符)、OFS(输出分隔符)、RS(行分隔符)、NF(字段数量)、NR(行号)、FNR(与NR相对,当读取多个文件时用于区分文件)、(当前行的整行内容)和(当前行的整行内容)和n(当前行的第n个字段)。
awk可以用于数据统计、文本过滤、报告生成等多种任务,其输入可以来自标准输入、文件或管道。awk还支持逻辑操作符(如&&、||、!),简单的数学运算和流程控制语句。在awk中,模式和操作可以单独使用,也可以组合使用,以实现复杂的文本处理需求。
总的来说,awk是一个功能强大的文本处理工具,广泛应用于数据分析和报告生成等领域。它通过其独特的语法和内置功能,使得复杂的文本处理任务变得相对简单。
2. awk
命令结构
awk 'BEGIN{commands} pattern{command} END{command}'
awk工作原理
- 第一步:执行
BEGIN{action}
语句块中的语句,该语句块不依赖于文件,awk在执行是将在读取文件之前执行该语句中的语句块,常用语变量的初始化,打印输出表格的表头。 - 第二步:从文件、标准输入、上一条命令输出结果输入到一行,然后进行
pattern{command}
语句块,它将逐行扫描文件,从第一行到最后一行。若没有提供pattern语句,则默认执行打印{print}
,即打印每一个读取到的行。 - 第三步:当读至文件最后时,执行
END{action}
语句块。通常用于汇总在pattern语句中执行的过程
下面我们来学习这个命令的使用
2.1 基本用法
awk [options] '[条件类型] 1{动作 1} 条件类型 2{动作 2} ...' filename
选项类型:
-F[]
:指明输入字段分隔符;默认以空白为分隔符。例如-F[,]
,以逗号为分隔符-v var=value
:变量赋值,无须声明,可直接调用-f /path/awk_script
:从awk脚本文件读取条件
条件类型:
后续展开介绍
常用动作:
print
:print在显示多个结果的时候以逗号分隔,结果将这几部分的内容自动使用输出分隔符(字段输出分割符默认是空格,记录输出分割符默认是换行符)进行分隔,且不需要添加换行符`\n;如果不使用,间隔,则打印时会连在一起,即使使用了空格printf
:printf可以更加灵活的控制某一个字段的输出格式,通过使用诸如%-12s,%3.1f
等格式化方法。printf更加接近使用C语言的同学的习惯
#-F
[root@node-249 test]# awk -F[:] '{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
...
#-v
[root@node-249 test]# awk -F[:] -v f1=1 -v f2=3 '{print $f1,$f2}' /etc/passwd
root 0
bin 1
...
#-F []可缺省
[root@node-249 test]# awk -F: -v f1=1 -v f2=3 '{print $f1,$f2}' /etc/passwd
root 0
bin 1
daemon 2
...
[root@node-249 test]# last -n 5|awk '{print $1,$3 }'
root 10.0.82.22
root 192.168.115.1
root 10.0.82.22
root Tue
reboot boot
wtmp Thu
[root@node-249 test]# last -n 5|awk '{print $1 "\t" $3 }'
root 10.0.82.22
root 192.168.115.1
root 10.0.82.22
root Tue
reboot boot
wtmp Thu
[root@node-249 test]# last -n 5|awk '{printf("%s,%s\n",$1,$3)}'
root,10.0.82.22
root,192.168.115.1
root,10.0.82.22
root,Tue
reboot,boot
,
wtmp,Thu
[root@node-249 test]# cat awk.script
{print $1,$3}
[root@node-249 test]# awk -f awk.script -F: /etc/passwd
root 0
bin 1
daemon 2
awk
后面接两个单引号
并加上大括号 {}
来设定想要对数据进行的处理动作。 awk 可以处理后续接的文件,也可以读取来自前个指令的 standard output 。 但如前面说的, awk 主要是处理『每一行的字段内的数据』,而默认的『字段的分隔符为 “空格键” 或 “[tab]键” 』!
2.2 变量
内置变量
变量名 | 说明 |
---|---|
$0 | 表示整个输入记录。 |
$n | 表示输入记录的第n个字段。 |
NF | 表示字段数量变量,在处理记录时,它表示当前记录的字段数。 |
NR | 表示记录的数量变量,在处理文件时,它表示当前处理的是第几行。 |
FS | 表示字段分隔符,默认是空格或Tab。 |
OFS | 表示输出字段分隔符,默认也是空格。 |
FILENAME | 表示当前输入文件的名字。 |
RS | 表示记录分隔符,用于定义输入时的换行符,默认是换行符。 |
ORS | 表示输出记录分隔符,用于定义输出时的换行符,默认也是换行符。 |
ARGC | 命令行参数数量 |
ARGV | 命令行参数属组 |
注意:在 awk 内的 NR, NF 等变量要用大写,且不需要有钱字号 $
[root@node-249 test]# awk -F: '{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
...
[root@node-249 test]# awk -F: '{print $1}' /etc/passwd
root
bin
daemon
...
[root@node-249 test]# awk -F: '{print NF}' /etc/passwd
7
7
7
...
[root@node-249 test]# awk -F: '{print NR,$1}' /etc/passwd
1 root
2 bin
3 daemon
[root@node-249 test]# awk -v FS=":" '{print $1,$3}' /etc/passwd|head -3
root 0
bin 1
daemon 2
[root@node-249 test]# awk -F: '{print $1,$3}' /etc/passwd|head -3
root 0
bin 1
daemon 2
[root@node-249 test]# awk -F: -v OFS="#" '{print $1,$3}' /etc/passwd|head -3
root#0
bin#1
daemon#2
[root@node-249 test]# awk -F: -v OFS="#" '{print $0,FILENAME}' /etc/passwd|head -3
root:x:0:0:root:/root:/bin/bash#/etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin#/etc/passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin#/etc/passwd
[root@node-249 test]# awk -v RS=":" '{print $0}' /etc/passwd|head -3
root
x
0
[root@node-249 test]# awk -v FS=":" -v ORS="#" '{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash#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#sync:x:5:0:sync:/sbin:...
[root@node-249 test]# awk -v FS=":" '{print ARGC}' /etc/passwd|head -3
2
2
2
[root@node-249 test]# awk -v FS=":" '{print ARGV[1]}' /etc/passwd|head -3
/etc/passwd
/etc/passwd
/etc/passwd
[root@node-249 test]# awk -v FS=":" '{print ARGV[0]}' /etc/passwd|head -3
awk
awk
awk
外置变量(自定义变量)
在awk命令中,我们可以使用-v
选项设置一个外置变量,这个变量可以在awk程序中使用
定义方法:
-v varName=value
[root@node-249 ~]# awk -v myVar="$var" 'BEGIN{print myVar}'
hello
[root@node-249 ~]# awk -v myVar="$var" 'BEGIN{print "\""myVar"\""}'
"hello"
2.3 执行流程
awk 'BEGIN{commands} pattern{command} END{command}'
- 读取输入文件之前执行的代码段(由关键字
BEGIN
标识) - 主循环执行输入文件的代码段
- 读取输入文件之后的代码段(由关键字
END
标识)
执行顺序简述:
1. BEGIN{} : 最开始执行
2. // : 正则
3. {} : 循环体
4. END{} : 最后执行
这里面最少有一个,最多有四个!
一个比较完整的示例语句
[root@node-249 ~]# cat /etc/passwd|awk 'BEGIN {FS=":";print "begin content"} $3<100{print $1,$3,$6} END{print "end content"}'
begin content
root 0 /root
bin 1 /bin
daemon 2 /sbin
...
ntp 38 /etc/ntp
end content
awk语句简解:
5. 首先执行BEGIN {FS=":";print "begin content"}
,其中定义了分隔符为:
,打印begin content
6. 执行正则表达式$3<100
,确认从/etc/passwd
中获取的每行内容的第三段(即UID
)小于100的满足条件
7. 执行循环体{print $1,$3,$6}
,打印第一、三、六段内容
8. 所有循环结束,执行END{print "end content"}
,打印end content
2.4 BEGIN模块
- 第一个作用,内置变量定义
[root@node-249 ~]# ip a show dev ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:39:d0:a6 brd ff:ff:ff:ff:ff:ff
inet 10.0.82.254/24 brd 10.0.82.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe39:d0a6/64 scope link
valid_lft forever preferred_lft forever
[root@node-249 ~]# ip a show dev ens33|awk 'BEGIN{FS="inet |/24"} NR==3{print $2}'
10.0.82.254
[root@node-249 ~]# ip a show dev ens33|awk 'BEGIN{FS="[ /]+"} NR==3{print $3}'
10.0.82.254
[root@node-249 ~]# ip a show dev ens33|awk 'BEGIN{FS="[^0-9.]+"} NR==3{print $2}'
10.0.82.254
- 第二个作用,读取文件之前,输出提示性信息(例如,表头)
[root@node-249 ~]# awk -F: 'BEGIN{print "username","UID"}{print $1,$3}' /etc/passwd |head -5
username UID
root 0
bin 1
daemon 2
adm 3
- 第三个作用,使用BEGIN模块的特殊性质,进行一些测试
#变量,赋值,计算
[root@node-249 ~]# awk 'BEGIN{a=1;b=2;print a,b,a+b}'
1 2 3
#计算
[root@node-249 ~]# awk 'BEGIN{print 10/3}'
3.33333
#打印
[root@node-249 ~]# awk 'BEGIN{print "hello, world!"}'
2.5 pattern模块
关于匹配模式,在帮助文档中,我们可以看到
Patterns
AWK patterns may be one of the following:
BEGIN
END
BEGINFILE
ENDFILE
/regular expression/
relational expression
pattern && pattern
pattern || pattern
pattern ? pattern : pattern
(pattern)
! pattern
pattern1, pattern2
排除BEGIN
和END
模式,大体可以分三种,即
- 正则表达式
/reg/
- 判断表达式
express
,例如前文中提到的$3<100
,$5 != 10 || $3 ==3
- 范围表达式
/pattern1/,/pattern2/
1. awk中的正则表达式
字符串匹配模式 (string-matching pattern) :测试一个字符串是否包含一段可以被正则表达式匹配
- (1)
/reg/
匹配整个输入行有没有使用默认的字段,即使用$0
[root@node-249 ~]# awk -F: '/root/ {print $1,$3,$6}' /etc/passwd
root 0 /root
operator 11 /root
- (2)
~/reg/
匹配单个被分隔的项目是否被匹配,比如$1,$2
[root@node-249 ~]# awk -F: '$1 ~ /root/ {print $1,$3,$6}' /etc/passwd
root 0 /root
[root@node-249 ~]# awk -F: '$1~ /root/ {print $1,$3,$6}' /etc/passwd
root 0 /root
[root@node-249 ~]# awk -F: '$1 ~/root/ {print $1,$3,$6}' /etc/passwd
root 0 /root
~
两侧有无空格均可
- (3)
!~/reg/
不包含为true
[root@node-249 ~]# awk -F: '$1 !~/root/ {print $1,$3,$6}' /etc/passwd
bin 1 /bin
daemon 2 /sbin
adm 3 /var/adm
...
awk支持regular符号表见下(元字符)
元字符 | 含义 | 例子 |
---|---|---|
\ | 转义字符 | awk -F "||" {print $1} worker.txt //打印每条记录的第1个字段 |
^ | 匹配一行的开始,在[]中表示非 | awk '/^[^U]/ {print}' countries //匹配不以U为开头的记录 |
$ | 匹配一行的结束 | awk '/a$/ {print}' countries //记录匹配以a为结尾 |
[ ] | [ ] 匹配一个范围如:[A-Za-z]或[^0-9] | awk '$1~/[A-G]/ {print $0}' countries //第1个字段匹配存在A-G字母(范围) |
| | 或 | awk '$1~/A|B/ {print $0}' countries //第1个字段匹配存在A或B字母 |
( ) | 匹配一个字符串 | awk '$1~/(USA)/ {print $0}' countries //第1个字段匹配为USA的记录 |
. | 匹配任意1个字符(有且仅有1个) | awk '$4 ~/^A..a$/ {print}' countries //第4个字段匹配以A开头且结尾为a的4个字符的 |
+ | 匹配1或多个字符 | awk '$1~/US+/ {print $0}' countries //第1个字段匹配存在US或USS等多个S |
? | 匹配 0 或 1个字符 | awk '$1~/S?/ {print $0}' countries //第1个字段匹配存在0或1个S |
* | 匹配0或多个字符 | awk '$1~/S*/ {print $0}' countries //第1个字段匹配存在0或多个个S |
awk中正则的组合符号主要是直接组合(reg1)(regs)
或reg1|reg2
比如:(Asian|European|North American) (male|female) (black|blue)bird
一共匹配12种字符串,由Asian male blackbird
到North American female bluebird
以3**Mario||27||female||Japan
为例,如果要分割该行
[root@node-249 ~]# cat awk1.txt|awk -F"\|\||\*\*" '{print $1}'
awk: warning: escape sequence `\|' treated as plain `|'
awk: warning: escape sequence `\*' treated as plain `*'
3
[root@node-249 ~]# cat awk1.txt|awk -F"|||**" '{print $1}'
3
[root@node-249 ~]# cat awk1.txt
3**Mario||27||female||Japan
由[]
(范围-互补)中,内部的字符即使需要直接对元字符的匹配也不需要进行转义,
[root@node-249 ~]# cat awk1.txt
3**Mario||27||female||Japan
^123
[root@node-249 ~]# cat awk1.txt |awk "/^[^^]/"'{print $1}'
采用其余方式使用元字符进行字符串匹配的都需要对元字符进行转义
匹配以一个^
或多个^^
为首的字符串
[root@node-249 ~]# cat awk1.txt
3**Mario||27||female||Japan
^123
^^321
[root@node-249 ~]# cat awk1.txt |awk "/^(\^)+/"'{print $1}'
^123
^^321
2. awk中的判断表达式
该模式主要是 常规运算符如: <,>..
,配合常规逻辑运算符 &&,||..
等使用,使用方式类似于:
if(express){
//do something
}
[root@node-249 ~]# ll | awk 'NR >1 {print}'
-rw-------. 1 root root 1260 Feb 2 2023 anaconda-ks.cfg
-rw-r--r-- 1 root root 9027 May 28 10:59 a.txt
-rw-r--r-- 1 root root 136 Jun 14 14:42 awk1.sh
-rw-r--r-- 1 root root 39 Jun 17 18:17 awk1.txt
drwxr-xr-x 2 root root 140 Jul 5 2023 bin
[root@node-249 ~]# ll | awk '$5 >4096 {print}'
-rw-r--r-- 1 root root 9027 May 28 10:59 a.txt
-rw-r--r-- 1 root root 2025407 May 6 15:20 default.json
-rw-r--r-- 1 root root 1693394 May 6 16:10 default.json.bak
-rw-r--r-- 1 root root 8486976 Jul 3 2023 docker-compose-Linux-x86_64
-rw-r--r-- 1 root root 32491520 May 28 11:02 jobs.tar
3. 范围表达式
范围模式由一个逗号分开的两个正则表达式组成,范围匹配如:/reg1/,/reg2/
[root@node-249 ~]# awk 'BEGIN{FS=":"} $1 ~/root/,/lp/ {print $1}' /etc/passwd
root
bin
daemon
adm
lp
[root@node-249 ~]# awk '/USSR/,/China/ {print}' test1
USSR 8649 275 Asia
Canada 3852 25 North America
China 3705 1032 Asia
[root@node-249 ~]# awk '/USSR/,/^[C]/ {print}' test1
USSR 8649 275 Asia
Canada 3852 25 North America
[root@node-249 ~]# cat test1
USSR 8649 275 Asia
Canada 3852 25 North America
China 3705 1032 Asia
USA 3615 237 North America
Brazil 3286 134 South America
India 1267 746 Asia
Mexico 762 78 North America
France 211 55 Europe
Japan 144 120 Asia
2.6 END模块
END
在awk读取完所有的文件的时候,再执行END
模块,一般用来输出一个结果(累加,数组结果),也可以是和BEGIN模块类似的结尾标识信息。与BEGIN格式一样,但是END模式仅在awk处理完所有输入行后才进行处理。
如果awk作为bash中处理文本的一个工具,那么笔者上面整理的基本满足需求了。但如果当做一个语言学习,那还远远不够。
awk还包括判断,循环,函数等等高级功能,笔者这里只是简单整理了日常可能用到的功能。如果想深入学习,不妨看看书