一、初识AWK
AWK
有其他的衍生版本,比如nawk
和gawk
,在Linux发行版里,默认使用的是gawk
:
# ls -l `which awk`
lrwxrwxrwx. 1 root root 4 5月 9 20:25 /usr/bin/awk -> gawk
二、AWK的工作流程
AWK
是按行处理文本,将行按照某一分隔符进行分割,其中分割之后的第一部分为$1
,第二部分为$2
,依次类推,其中$0
表示整行,超过10的要将数字用括号括起来,比如$(10)
AWK
默认的分隔符是空格和tab
,其中操作命令必须写在{}里面,语法:
awk '/模式/{print $1}' file //模式支持正则表达式,只对含有该模式的行进行操作
- 可以使用
-F
选项指定分隔符:
awk -F: '/模式/{print $1}' file
三、常见操作符的使用(例子中passwd文件使用/etc/passwd文件的前6行)
常见的操作符有:~
、!~
、==
、!=
、>
、<
、++
、--
等
~
和!~
表示包含和不包含:
# awk -F: '$1~/ro/{print $0}' passwd
root:x:0:0:root:/root:/bin/bash
==
和!=
表示严格的等于和不等于:
# awk -F: '$3==1{print $0}' passwd
bin:x:1:1:bin:/bin:/sbin/nologin
# awk -F: '{$3++;print $3}' passwd
1
2
3
4
5
6
- 其他的一些操作符同理,两个以上的条件需要使用连接符
&&
或||
四、AWK中 BEGIN 和 NED 的用法
BEGIN
中的命令是在AWK读取文本的第一行之前进行操作:
# awk -F: 'BEGIN{print "用户名"}{print $1}' passwd
用户名
root
bin
daemon
adm
lp
sync
END
中的命令是在读取完最后一行之后进行的操作:
# awk -F: '{print $1}END{print "结束"}' passwd
root
bin
daemon
adm
lp
sync
结束
- BEGIN和END可以同时出现,也可以单独出现,BEGIN中可以定义变量:
# awk -F: 'BEGIN{a=1}{print a}' passwd
1
1
1
1
1
1
如何没有预先定义变量的话,在后面也是可以引用的,只不过这个变量的值为空。引用变量的时候不加$
END
中也可以进行最终的计算:
# awk -F: 'BEGIN{sum=0}{sum+=$3}END{print "所有UID的和为:"sum}' passwd
所有UID的和为:15
或者不预先定义变量:
# awk -F: '{sum+=$3}END{print "所有UID的和为:"sum}' passwd
所有UID的和为:15
五、AWK中常见内置变量的用法
FS
代表分隔符:
# awk 'BEGIN{FS=":"}{print $1}' passwd
root
bin
daemon
adm
lp
sync
OFS
为打印输出的分隔符,默认的是空格:
# awk 'BEGIN{FS=":";OFS="---"}{print $1,$2}' passwd
root---x
bin---x
daemon---x
adm---x
lp---x
sync---x
NF
的值表示将每一行按照FS
指定的分隔符分为多少段:
# awk 'BEGIN{FS=":"}{print NF}' passwd
7
7
7
7
7
7
如果要打印每一行的最后一段,可以使用以下用法:
# awk 'BEGIN{FS=":"}{print $NF}' passwd
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/bin/sync
- 前面提到过,AWK是将文件按行进行处理,那么AWK是如何分别每一行的呢?使用的就是
RS
的值,默认为\n
:
# cat test.txt
1,张三:经理 2,李四:职员 3,王五:老板
# awk -F[:,] 'BEGIN{RS=" "}{print $2,$3}' test.txt
张三 经理
李四 职员
王五 老板
ORS
变量的值决定输出行的分隔符,默认的为\n
:
# awk 'BEGIN{ORS="---"}{print $0}' 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:/bin/sync---
FILENAME
变量的值为当前操作文件的文件名:
# awk -F: '{print FILENAME}' passwd
passwd
passwd
passwd
passwd
passwd
passwd
NR
变量的值表示当前正在操作的行号:
# awk -F: '{print NR}' passwd
1
2
3
4
5
6
如果这里将行分隔符RS
赋值为-
,验证NR
的值:
# awk 'BEGIN{RS="-"}{print NR}' passwd
1
FNR
也表示当前操作的行号,不同的是,当对一个文件进行操作的时候FNR
和NR
的值是一样的。当对两个文件进行操作时,FNR
和NR
的值是不一样的:
# awk -F: '{print NR,$1,FNR}' passwd shadow
1 root 1
2 bin 2
3 daemon 3
4 adm 4
5 lp 5
6 sync 6
7 root 1
8 bin 2
9 daemon 3
10 adm 4
11 lp 5
12 sync 6
六、判断和循坏语句
if
语句:
语法,如果语句没有使用{},则要使用;分隔
if(判断1){语句1}else if(判断2){语句2}else{语句3}
if(判断1)语句1;else if(判断2)语句2;else语句3
# awk -F: '{if($3==0){print $1"是root"}else if($3>=1000){print $1"是普通用户"}else{print $1"是系统用户"}}' passwd
root是root
bin是系统用户
daemon是系统用户
adm是系统用户
lp是系统用户
sync是系统用户
for
循坏语句:
awk -F: '{for(i=1;i<=NF-5;i++){print $i}}' passwd
root
x
bin
x
daemon
x
while
循坏语句:
# awk -F: '{print "------------";i=1;while(i<=NF){print $i;i++}}' 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
- 循坏控制语句
break
:
break只能用在循环语句中,作用是跳出当前循环,继续下一循环
# echo -e "1 2 3 4 1\n5 6 7" | awk '{for(i=1;i<=NF;i++){if($i>=2){break}print $i}}'
1
- 循环控制语句
continue
:如果遇到continue,continue后面的语句不再执行,继续下一个循环
# echo -e "1 2 3 4 1\n5 6 7" | awk '{for(i=1;i<=NF;i++){if($i>=2){continue}print $i}}'
1
1
- 循环控制语句
next
:遇到next,跳出循环,继续下移循环,在循环语句中next和break语句效果一样。区别在于,break和continue语句只能用于循环语句,next语句还可以用于其他语句,以下例子用于判断语句
# echo -e "1 2 3 4 1\n5 6 7 1" | awk '{if($2<=2){next}print $0}'
5 6 7 1
# awk -F: 'NR==FNR{print NR,FILENAME,FNR;next}{print NR,FILENAME,FNR}' passwd shadow
1 passwd 1
2 passwd 2
3 passwd 3
4 shadow 1
5 shadow 2
6 shadow 3
七、AWK中数组的使用
- 手动定义数组
# echo '' | awk '{aa[1]=1;aa[2]=2;aa["b"]="b";print aa[1]}'
1
- 读取文件
# awk -F: '{for(i=1;i<=NF;i++){a[i]=$i;print a[1];break}}' passwd
root
bin
daemon
# cat c1
01 北京
02 上海
03 广州
04 深圳
# cat c2
01 beijing
02 shanghai
03 guangzhou
04 shenzhen
# awk 'NR==FNR{a[$1]=$0}NR!=FNR{print a[$1],$2}' c1 c2
01 北京 beijing
02 上海 shanghai
03 广州 guangzhou
04 深圳 shenzhen
八、AWK中常见函数的使用
sub
和gsub
函数:用来替换
# cat test.txt
tom bob mary tom
bob tom mary tom
# awk '{sub("tom","TOM");print}' test.txt
TOM bob mary tom
bob TOM mary tom
但是只替换了每行的第一个,要想替换所有的,使用gsub
函数:
# awk '{gsub("tom","TOM");print}' test.txt
TOM bob mary TOM
bob TOM mary TOM
只替换最后一个:
# awk '{gsub("tom","TOM",$NF);print}' test.txt
tom bob mary TOM
bob tom mary TOM
length
函数用来计算字符串长度
# awk -F: '{print $1,length($1)}' passwd
root 4
bin 3
daemon 6
substr
函数用来截取一段数据
# awk -F: '{print substr($1,2)}' passwd
oot
in
aemon
# awk -F: '{print substr($1,2,2)}' passwd
oo
in
ae
match
函数的使用,从字符串中匹配满足某种格式的位置
# awk -F: '{xx=match($1,"oo");print xx}' passwd
2
0
0
match
中有两个变量,RSTART
可以获取到match
得到的值,RLENGTH
表示的是match
中满足格式的字符创的长度,一般会结合substr截取我们所需要的数据:
# awk -F: '{xx=match($1,"oo");print xx,RSTART,RLENGTH}' passwd
2 2 2
0 0 -1
0 0 -1
split
函数的使用:split("原始字符串",数组名,<分隔符>)
# echo '' | awk '{split("2018-05-20",xx,"-");print xx[1],xx[2],xx[3]}'
2018 05 20
# awk '{split($0,xx,":");print xx[1]}' passwd
root
bin
daemon
getline
函数可以让我们使用操作系统命令,也可以读取另一个文件内容
# awk '{getline;print $0}' c1
02 上海
04 深圳
可以看到getline
将本文件的下一行赋值给当前的$0
# awk '{getline xx;print $0,xx}' c1
01 北京 02 上海
03 广州 04 深圳
在这里将下一行的值赋值给了getline后的变量xx,并没有影响当前的$0
getline < file
:该用法读取file文件的一行赋值给当前的$0
getline xx < file
:该用法读取file文件的一行赋值给变量xx
# awk '{getline xx< "c2";print xx,$2}' c1
01 beijing 北京
02 shanghai 上海
03 guangzhou 广州
04 shenzhen 深圳
# echo '' | awk '{"date"|getline xx;print xx}'
2018年 05月 20日 星期日 19:57:04 CST
# echo '' | awk '{while("ls /boot"|getline xx) print xx}'
config-3.10.0-327.el7.x86_64
grub2
initramfs-0-rescue-ba7506401e184ceea617517542f6b7c7.img
initramfs-3.10.0-327.el7.x86_64.img
initrd-plymouth.img
symvers-3.10.0-327.el7.x86_64.gz
System.map-3.10.0-327.el7.x86_64
vmlinuz-0-rescue-ba7506401e184ceea617517542f6b7c7
vmlinuz-3.10.0-327.el7.x86_64
# echo '' | awk '{print "请输入:";getline name<"/dev/tty";print "你好:" name}'
请输入:
tom
你好:tom
九、AWK的格式化输出
printf
不带换行符
# awk -F: '{printf "%-8s|%-5d\n",$1,$3}' passwd
root |0
bin |1
daemon |2
其中%-8s
中的-8表示显示宽度为8个字符,-
表示左对齐,+
号表示右对齐
%d
显示的整数
%f
显示的是浮点数,%10.5f
表示总共显示十位。小数点后显示5位
%e
用科学计数法显示
# echo '' | awk '{printf "%d\n",3*3.5}'
10
# echo '' | awk '{printf "%f\n",3*3.5}'
10.500000
# echo '' | awk '{printf "%-.10f\n",10/3}'
3.3333333333
# echo '' | awk '{printf "%e\n",3*3.5}'
1.050000e+01
✅ @pmliang, I gave you an upvote on your first post! Please give me a follow and I will give you a follow in return!
Please also take a moment to read this post regarding bad behavior on Steemit.
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit
thank you
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit