awk用法
概念:
AWK是一种强大的文本处理工具,它可以用于从文件或标准输入流中提取和操作数据。AWK是一种用于处理和操作文本文件的编程语言。它的名字来源于其创始人Alfred Aho、Peter Weinberger和Brian Kernighan的姓氏的首字母。
AWK提供了一种简单而强大的方式来搜索、过滤、提取和转换文本数据。它以行为单位读取输入文件,并根据用户指定的模式和操作来处理每一行。
AWK的基本工作原理是,它将每一行拆分成字段(默认使用空格作为分隔符),然后可以使用各种内置函数和操作符来操作和处理这些字段。AWK还支持用户自定义函数和变量,使其更加灵活和可扩展。
AWK常用于数据处理、报告生成、文本转换和格式化等任务。它在UNIX和类UNIX系统中广泛使用,并且有许多变种和扩展版本可用。
常用用法概括:
- AWK是一种命令行工具,用于处理结构化文本数据。
- AWK将输入文件或标准输入流分解为记录(行)和字段(列)。
- AWK使用模式-动作语法来指定要执行的操作。
- AWK的默认操作是打印整个记录,可以通过指定模式来选择特定记录进行处理。
- AWK提供了许多内置变量,如0表示整个记录,1表示第一个字段,NF表示字段的数量等。
- AWK支持各种算术运算、条件语句、循环和函数。
- AWK可以读取文件、处理文本、格式化输出等。
用法:
awk '/hello/ {print}' file.txt
// /hello/是模式,它匹配包含"hello"的行。{print}是操作,它打印匹配的行
基础打印演示
[root@localhost ~]# echo | awk '{print "hello world"}' //awk必须有一个对象
hello world //echo后面的东西作为awk的载体
[root@localhost ~]# echo -e " \n \n" | awk '{print "hello world"}'
hello world //\n表示换行
hello world
hello world //-e:告诉 echo 命令对转义序列进行解释
//单独打印一个文件里面的内容
[root@localhost ~]# cat a
jbdcnw
wmcjb
wncj
wncj
wnje3furgt
nejvhtb4el
[root@localhost ~]# awk '{print}' a
jbdcnw
wmcjb
wncj
wncj
wnje3furgt
nejvhtb4el
打印:对文件进行操作 文件有多少行打印多少行
[root@localhost ~]# cat a
jbdcnw
wmcjb
wncj
wncj
wnje3furgt
nejvhtb4el //文件有六行
[root@localhost ~]# awk '{print "hello world"}' a
hello world
hello world
hello world
hello world
hello world
hello world
//匹配到文件里面的空行并打印
[root@localhost ~]# cat a
jbdcnw
wmcjb
wncj
nejvhtb4el
[root@localhost ~]# awk '/^$/{print "This is a blank line."}' a
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
awk -F
意思是指定字段分隔符。默认情况下,awk使用空格作为字段分隔符,但可以使用-F选项来指定其他字符作为分隔符。例如,使用awk -F:将冒号作为字段分隔符。
//打印/etc/passwd第一列内容
[root@localhost ~]# awk -F: '{print $1}' /etc/passwd
root //$1表示第一列
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp
nobody
dbus
systemd-coredump
systemd-resolve
tss
polkitd
unbound
sssd
sshd
apache
mysql
//将tab键当做换行符
[root@localhost ~]# cat abc //666前面的空格为tab键
John Robinson 666-555-1111
[root@localhost ~]# awk -F'\t' '{print $2}' abc
666-555-1111 //打印第二个字符,将John Robinson当做一个字符
或者:
[root@localhost ~]# awk 'BEGIN{FS="\t"}{print $2}' abc
666-555-1111
FS=”\t“ //将每个制表符作为一个字段分隔符
FS=”\t+“ //用一个或者多个制表符来分隔字段
\n:换行符
\r:回车
\t:水平制表符
\v:垂直制表符
//取ip
[root@localhost ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:51:4c:69 brd ff:ff:ff:ff:ff:ff
inet 192.168.134.148/24 brd 192.168.134.255 scope global dynamic noprefixroute ens160
valid_lft 1557sec preferred_lft 1557sec
inet6 fe80::20c:29ff:fe51:4c69/64 scope link noprefixroute
valid_lft forever preferred_lft forever
第一种:
[root@localhost ~]# ip a | grep 'inet ' | grep -v '127' | awk '{print $2}' | awk -F'/' '{print $1}'
192.168.134.148
第二种:
[root@localhost ~]# ip a | grep 'inet ' | grep -v '127'
inet 192.168.134.148/24 brd 192.168.134.255 scope global dynamic noprefixroute ens160
[root@localhost ~]# ip a | grep 'inet ' | grep -v '127' | awk -F'[ /]+' '{print $3}'
192.168.134.148 //将空格和/当作分隔符
注:默认情况下空格和tab键是一样的,除非特别定义tab键为分隔符
awk三大部分:
BEGIN(必须大写):表示开始的意思(此时不需要任何处理对象)
{}:(主体)
END:不能直接使用 必须与前面两个或者其中之一一起使用
语法:awk ‘BEGIN{""} {} END{}’ //awk里面必须用双引 awk默认分隔符是空格
//BENGIN和END是可选的可以没有
BEGIN:(里面必须用” “)
//有几行空格打印几行字段
[root@localhost ~]# cat a
jbdcnw
wmcjb
wncj
nejvhtb4el
[root@localhost ~]# awk 'BEGIN{print}/^$/{print "This is a blank line."}' a
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
记录和字段
$0:表示整个参数
$1:表示第一个参数
$2:表示第二个参数
$3:表示第三个参数
//打印第一段字符
[root@localhost ~]# cat abc
John Robinson 666-555-1111 //默认的分隔符为”空格“
[root@localhost ~]# awk '{print $1}' abc
John
//打印第一段,第二段,第三段字符 //表示指定分隔符为,
[root@localhost ~]# awk '{print $1,$2,$3}' abc
John Robinson 666-555-1111
//不加,打印字符 //表示没有指定分隔符
[root@localhost ~]# awk '{print $1$2$3}' abc
JohnRobinson666-555-1111
//加:打印 //表示指定分隔符为:
[root@localhost ~]# awk '{print $1":"$2":"$3}' abc
John:Robinson:666-555-1111
//可调换位置
[root@localhost ~]# awk '{print $1,$3,$2}' abc
John 666-555-1111 Robinson
awk运算加减乘除,乘方,余数
//定义变量
[root@localhost ~]# echo a b c d |awk 'BEGIN {one=1;tow=2}{print $(one+tow)}'
c
//加
[root@localhost ~]# awk 'BEGIN{print 10+10}'
20
//减
[root@localhost ~]# awk 'BEGIN{print 10-1}'
9
//乘
[root@localhost ~]# awk 'BEGIN{print 12*2}'
24
//除
[root@localhost ~]# awk 'BEGIN{print 12/2}'
6
//乘方 取幂:^或者**
[root@localhost ~]# awk 'BEGIN{print 3**2}'
9
[root@localhost ~]# awk 'BEGIN{print 2^3}'
8
//取余数
[root@localhost ~]# awk 'BEGIN{print 3%2}'
1
表达式
//实例
[root@localhost ~]# cat abc
John Robinson 666-555-1111
[root@localhost ~]# awk 'BEGIN{a= "hello world"}{print a}' abc
hello world
//设置变量a为hello world 并打印(abc里面有多少行内容就打印多少行)
用定义变量的方式来计算
[root@localhost ~]# cat abc
John Robinson 666-555-1111
[root@localhost ~]# awk 'BEGIN{x=1;y=x+1}{print y}' abc
2 //必须有载体(abc),此处的abc里面只有一行内容所以结果打印一遍
操作符
++ 变量加1
-- 变量减1
+= 将加的结果赋给变量
-= 将减的结果赋给变量
*= 将乘的结果赋给变量
/+ 将除的结果赋给变量
%= 将取模的结果赋给变量
^= 将取幂的结果赋给变量
**= 将取幂的结果赋给变量
实例:
[root@localhost ~]# cat abc
John Robinson 666-555-1111
jshb
sh
smhgd
wjh
[root@localhost ~]# awk '/^$/{print x+=1}' abc //表示将1赋值到空行上面并持续加
1
2
3
4
5
[root@localhost ~]# awk '/^$/{print x++}' abc //先打印再加
0
1
2
3
4
[root@localhost ~]# awk '/^$/{print ++x}' abc //先加再打印
1
2
3
4
5
[root@localhost ~]# awk '/^$/{++x}END{print x}' abc //显示总行数
5
[root@localhost ~]# awk '{++x}END{print x}' abc //打印文件的总行数
10
计算学生的成绩
[root@localhost ~]# cat grand
huxianxun 98 87 79 83 66
xiaozhan 99 100 83 89 79
luoyaoyao 83 24 25 26 27
//总分
[root@localhost ~]# awk '{total=$2+$3+$4+$5+$6;print $1,total}' grand
huxianxun 413
xiaozhan 450
luoyaoyao 185
//平均分
[root@localhost ~]# awk '{total=$2+$3+$4+$5+$6;avg=total/5;print $1,avg}' grand
huxianxun 82.6
xiaozhan 90
luoyaoyao 37
系统变量
在AWK中,有一些系统变量提供了额外的信息和功能,可以在处理文本数据时使用。以下是一些常用的AWK系统变量:
1. FS(Field Separator):字段分隔符,默认为连续的空格或制表符。可以使用-F选项或在AWK脚本中使用FS变量来修改字段分隔符。
2. OFS(Output Field Separator):输出字段分隔符,默认为单个空格。可以在AWK脚本中使用OFS变量来修改输出字段分隔符。
3. RS(Record Separator):记录分隔符,默认为换行符。可以使用-v RS=选项或在AWK脚本中使用RS变量来修改记录分隔符。
4. ORS(Output Record Separator):输出记录分隔符,默认为换行符。可以在AWK脚本中使用ORS变量来修改输出记录分隔符。
5. NR(Number of Records):当前处理的记录数,从1开始递增。
6. NF(Number of Fields):当前记录中的字段数。
7. $0:当前记录的整行内容。
8. $1、$2等:当前记录中的第1、第2等字段内容。
9. FILENAME:当前输入文件的名称。
注:可以使用NF来判断记录中的字段数量是否满足某个条件
使用FILENAME来打印当前处理的文件名等。
注:系统变量是只读的,不能在AWK脚本中直接修改它们的值。如果需要修改字段分隔符、记录分隔符等,可以使用相应的选项或变量来实现。
awk中有许多系统变量和内置变量
第一种:类型定义变量默认值可以改变,列如:默认字段、记录分隔符
//定义分隔符
[root@localhost ~]# cat grand
huxianxun 98 87 79 83 66
xiaozhan 99 100 83 89 79
luoyaoyao 83 24 25 26 27
[root@localhost ~]# awk -F'83' '{print $1}' grand
huxianxun 98 87 79
xiaozhan 99 100
luoyaoyao
[root@localhost ~]# cat grand
huxianxun 98 87 79 83 66
xiaozhan 99 100 83 89 79
luoyaoyao 83 24 25 26 27
[root@localhost ~]# vim grand
[root@localhost ~]# awk -F'\t' '{print $1}' grand
huxianxun
xiaozhan 99 100 83 89 79
luoyaoyao 83 24 25 26 27
第二种:类型定义变量的值可用于报告或者数据处理。例如当前记录字段中的数量、当前记录的数量等
FS:输入 OFS:输出
将NF定义为当前输入字段的个数
将记录分隔符RS定义为一个换行符
FS定义输入分隔符
OFS定义输出分隔符
[root@localhost ~]# cat grand
huxianxun 98 87 79 83 66
xiaozhan 99 100 83 89 79
luoyaoyao 83 24 25 26 27
[root@localhost ~]# awk 'BEGIN{FS=" ";OFS=":"}{print $1,$3}' grand
huxianxun:87 //用FS定义输入时分隔符 用OFS定义输出分隔符
xiaozhan:100
luoyaoyao:24
[root@localhost ~]# awk 'BEGIN{FS=" ";OFS=":"}{print $1$3}' grand
huxianxun87
xiaozhan100
luoyaoyao24
运算
[root@localhost ~]# awk 'BEGIN{print (5.5+2.4) " is a nice value"}'
7.9 is a nice value
NR:行号
[root@localhost ~]# awk '{total=$2+$3+$4+$5+$6;avg=total/5;print NR ".", $1,avg}' grand
1. huxianxun 82.6
2. xiaozhan 90
3. luoyaoyao 37
//取ip
[root@localhost ~]# ip a | grep 'inet '
inet 127.0.0.1/8 scope host lo
inet 192.168.134.148/24 brd 192.168.134.255 scope global dynamic noprefixroute ens160
[root@localhost ~]# ip a | grep 'inet ' | awk -F'[ /]+' 'NR==2{print $3}'
192.168.134.148 //NR指向第二行
NF:表示列数
[root@localhost ~]# cat grand
huxianxun 98 87 79 83 66
xiaozhan 99 100 83 89 79
luoyaoyao 83 24 25 26 27
[root@localhost ~]# awk '{print NF}' grand //打印列数
6
6
6
[root@localhost ~]# awk '{print $NF}' grand //打印最后一列
66
79
27
[root@localhost ~]# awk '{print $(NF-1)}' grand //显示倒数第二行
83
89
26
总:
//取分区最后一列 NR:行号 NF:列号
[root@localhost ~]# df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 957M 0 957M 0% /dev
tmpfs 976M 0 976M 0% /dev/shm
tmpfs 976M 8.7M 967M 1% /run
tmpfs 976M 0 976M 0% /sys/fs/cgroup
/dev/mapper/rhel-root 17G 5.5G 12G 33% /
/dev/nvme0n1p1 1014M 177M 838M 18% /boot
tmpfs 196M 0 196M 0% /run/user/0
[root@localhost ~]# df -h | awk 'NR==1{print $(NF-1),$(NF)}'
Mounted on //当他是第一行的时候打印倒数两列
[root@localhost ~]# df -h | awk 'NR==1{print $(NF-1),$NF}{print $NF}'
Mounted on //当他是第一行的时候打印倒数两列,其他的打印最后一列
on
/dev
/dev/shm
/run
/sys/fs/cgroup
/
/boot
/run/user/0
//第一行的时候打印print $(NF-1),$NF,不是第一行的时候print $NF
[root@localhost ~]# df -h | awk 'NR==1{print $(NF-1),$NF}NR!=1{print $NF}'
Mounted on //NR!=1:不为1的时候
/dev
/dev/shm
/run
/sys/fs/cgroup
/
/boot
/run/user/0
RS:输入换行符
ORS:输出换行符
将换行符作为分隔符
[root@localhost ~]# cat a
John Robinson
Koren Inc
978 Commonwealth Ave
Boston
MA 01760
696-0987
[root@localhost ~]# awk 'BEGIN{FS="\n";RS=""}{print $1,$NF}' a
John Robinson 696-0987 //将换行符当作换行符,第一个字符就是第一行 最后一个字符就是最后一行
[root@localhost ~]# awk 'BEGIN{FS="\n";RS="";OFS="\n"}{print $1,$NF}' a
John Robinson
696-0987
[root@localhost ~]#awk 'BEGIN{FS="\n";RS="";OFS="\n";ORS="\n\n"}{print $1,$NF}' a
John Robinson
696-0987
//此处多出一个空格
[root@localhost ~]#
NEXT:(对后一条件生效)
[root@localhost ~]# cat b
1000
125 hbehc -125.22
126 jdbech hbec -34.95
127 jwjebvb -7.45
[root@localhost ~]# awk 'NR==1{print "begin balance:\t" $1}' b
begin balance: 1000
[root@localhost ~]# awk 'NR==1{print "begin balance:\t" $1;balance=$1}' b
begin balance: 1000 //此处balance=$1是定义的变量
[root@localhost ~]# awk 'NR==1{print "begin balance:\t" $1;balance=$1}{print $1,$2,$3}' b
begin balance: 1000
1000
125 hbehc -125.22
126 jdbech hbec
127 jwjebvb -7.45
[root@localhost ~]# awk 'NR==1{print "begin balance:\t" $1;balance=$1;next}{print $1,$2,$3}' b //next是对后面条件起作用
begin balance: 1000
125 hbehc -125.22
126 jdbech hbec
127 jwjebvb -7.45
关系表达式:
< 小于
> 大于
<= 小于等于
>= 大于等于
== 相等的
!= 不等的
~ 匹配
!- 不匹配
实例:
[root@localhost ~]# cat a
John Robinson
Koren Inc
978 Commonwealth Ave
Boston
MA 01760
696-0987
[root@localhost ~]# awk 'NF==1{print $0}' a
Boston //只有一列的时候打印这一整行
696-0987
//第一行打印最后两列,其他的打印最后一列
[root@localhost ~]# df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 957M 0 957M 0% /dev
tmpfs 976M 0 976M 0% /dev/shm
tmpfs 976M 8.7M 967M 1% /run
tmpfs 976M 0 976M 0% /sys/fs/cgroup
/dev/mapper/rhel-root 17G 5.5G 12G 33% /
/dev/nvme0n1p1 1014M 177M 838M 18% /boot
tmpfs 196M 0 196M 0% /run/user/0
[root@localhost ~]# df -h | awk 'NR==1{print $(NF-1),$NF;next}{print $NF}'
Mounted on
/dev
/dev/shm
/run
/sys/fs/cgroup
/
/boot
/run/user/0
布尔 操作符
操作符 定义
|| 逻辑或
&& 逻辑与
! 逻辑非
[root@localhost ~]# ll
total 11228
-rw-r--r-- 1 root root 70 Sep 19 14:20 a
-rw-r--r-- 1 root root 63 Sep 18 01:57 ab
-rw-r--r-- 1 root root 50 Sep 18 16:37 abc
-rw-------. 1 root root 1086 Aug 5 23:36 anaconda-ks.cfg
drwxr-xr-x 29 501 games 4096 Aug 31 16:17 apr-1.7.4
-rw-r--r-- 1 root root 1122147 Apr 16 21:07 apr-1.7.4.tar.gz
drwxr-xr-x 21 501 games 4096 Aug 31 16:18 apr-util-1.6.3
-rw-r--r-- 1 root root 556623 Feb 2 2023 apr-util-1.6.3.tar.gz
-rw-r--r-- 1 root root 64 Sep 19 14:34 b
-rw-r--r-- 1 root root 77 Sep 18 17:28 grand
drwxr-xr-x 14 501 games 4096 Aug 31 16:19 httpd-2.4.57
-rw-r--r-- 1 root root 9773385 Apr 6 22:46 httpd-2.4.57.tar.gz
-rw-r--r-- 1 root root 20 Sep 18 01:17 jj
-rw-r--r-- 1 root root 0 Sep 15 18:44 lm
[root@localhost ~]# ll | awk '{print $5,"\t",$9}'
70 a
63 ab
50 abc
1086 anaconda-ks.cfg
4096 apr-1.7.4
1122147 apr-1.7.4.tar.gz
4096 apr-util-1.6.3
556623 apr-util-1.6.3.tar.gz
64 b
77 grand
4096 httpd-2.4.57
9773385 httpd-2.4.57.tar.gz
20 jj
0 lm
[root@localhost ~]# ll | awk '{sum+=$5;++filenum;print $5,"\t",$9}'
70 a
63 ab
50 abc
1086 anaconda-ks.cfg
4096 apr-1.7.4
1122147 apr-1.7.4.tar.gz
4096 apr-util-1.6.3
556623 apr-util-1.6.3.tar.gz
64 b
77 grand
4096 httpd-2.4.57
9773385 httpd-2.4.57.tar.gz
20 jj
0 lm
//总字节
[root@localhost ~]# ll | awk '{sum+=$5;++filenum;print $5,"\t",$9}END{print "Total: ",sum}'
70 a
63 ab
50 abc
1086 anaconda-ks.cfg
4096 apr-1.7.4
1122147 apr-1.7.4.tar.gz
4096 apr-util-1.6.3
556623 apr-util-1.6.3.tar.gz
64 b
77 grand
4096 httpd-2.4.57
9773385 httpd-2.4.57.tar.gz
20 jj
0 lm
Total: 11465873
[root@localhost ~]# ll | awk 'NR!=1{sum+=$5;++filenum;print $5,"\t",$9}END{print "Total: ",sum,"bytes (" filenum " file)"}' //此处一定要加NR!=1 避免将第一行total也加进来
70 a
63 ab
50 abc
1086 anaconda-ks.cfg
4096 apr-1.7.4
1122147 apr-1.7.4.tar.gz
4096 apr-util-1.6.3
556623 apr-util-1.6.3.tar.gz
64 b
77 grand
4096 httpd-2.4.57
9773385 httpd-2.4.57.tar.gz
20 jj
0 lm
Total: 11465873 bytes (14 file)
//BEGIN里面写的第一行内容,end里面写的是最后的内容
[root@localhost ~]# ll | awk 'BEGIN{print "bytes","\t","file"}NR!=1{sum+=$5;++filenum;print $5,"\t",$9}END{print "Total: ",sum,"bytes (" filenum " file)"}'
bytes file
70 a
63 ab
50 abc
1086 anaconda-ks.cfg
4096 apr-1.7.4
1122147 apr-1.7.4.tar.gz
4096 apr-util-1.6.3
556623 apr-util-1.6.3.tar.gz
64 b
77 grand
4096 httpd-2.4.57
9773385 httpd-2.4.57.tar.gz
20 jj
0 lm
Total: 11465873 bytes (14 file)
格式化打印
printf(不会自动加换行符)
[root@localhost ~]# awk 'BEGIN{printf "hello world"}'
hello world[root@localhost ~]#
print格式说明符
c ASCII字符
d 十进制整数
i 十进制整数
e 浮点格式
E 浮点格式
f 浮点格式
g e或f转换形式,长度最短,末尾的0被去掉
G E或f的转换形式,长度最短,末尾的0被去掉
O 无符号的八进制
s 字符串
u 无符号的十进制
x 无符号的十六进制,用a-f表示10-15
X 无符号的十六进制,用A-F表示10-15
% 字面字符%
实例:
[root@localhost ~]# ll | awk 'NR!=1{printf "%d\t%s\n",$5,$9}'
70 a d:整数 s:字符串
63 ab
50 abc
1086 anaconda-ks.cfg
4096 apr-1.7.4
1122147 apr-1.7.4.tar.gz
4096 apr-util-1.6.3
556623 apr-util-1.6.3.tar.gz
64 b
77 grand
4096 httpd-2.4.57
9773385 httpd-2.4.57.tar.gz
20 jj
0 lm
//字母
[root@localhost ~]# awk 'BEGIN{printf "|%10s|","hello"}'
| hello|[root@localhost ~]# //%10s表示总共10共字符
//当字符超出时,直接全部打印
[root@localhost ~]# awk 'BEGIN{printf "|%10s|","helloworldshshshhshhs"}'
|helloworldshshshhshhs|[root@localhost ~]#
//负数打印,向右填充
[root@localhost ~]# awk 'BEGIN{printf "|%-10s|","hello"}'
|hello |[root@localhost ~]#
//数字
//正数,向左填充
[root@localhost ~]# awk 'BEGIN{printf "|%10d|","100"}'
| 100|[root@localhost ~]#
//负数,向右填充
[root@localhost ~]# awk 'BEGIN{printf "|%-10d|","100"}'
|100 |[root@localhost ~]#
循环
//do循环
[root@localhost ~]# awk 'BEGIN{do{++i;print i}while (i<=4)}'
1 //while:条件 do:循环
2
3
4
5
//while语句
[root@localhost ~]# awk 'BEGIN{while(i<4){++i;print i}}'
1
2
3
4