标签:music 报告 common continue 特殊用法 switch语句 ati ks.cfg 文本处理三剑客
文件处理三剑客之AWKawk:Aho Weinberger Kernighan,报告生成器,格式化文本输出
awk [options] ‘program‘ var=value file…
awk [options] -f programfile var=value file…
awk [options] ‘BEGIN{action;… }pattern{action;… }END {action;… }‘ file ...
awk 程序可由:BEGIN语句块、能够使用模式匹配的通用语句块、 END语句块,共3部分组成
program 通常是被放在单引号中
-F “分隔符” 指明输入时用到的字段分隔符
-v var=value 变量赋值
awk [options] ‘program‘ file…
pattern{action statements;..}
pattern部分决定动作语句何时触发及触发事件
BEGIN,END
action statements对数据进行处理,放在{}内指明
print, printf
? awk执行时,由分隔符分隔的字段(域)标记$1,$2...$n称为域标识。 $0为所有域,注意:此时和shell中变量$符含义不同
? 文件的每一行称为记录
? 省略action,则默认执行 print $0 的操作
print item1, item2, ...
逗号分隔符
输出item可以字符串,也可是数值;当前记录的字段、变量或awk的表达式
如省略item,相当于print $0
内置变量和自定义变量
输入字段分隔符,默认为空白字符
[root@centos ~]# awk -v FS=: ‘{print $1,FS,$3}‘ /etc/passwd
root : 0
bin : 1
daemon : 2
adm : 3
lp : 4
sync : 5
shutdown : 6
halt : 7
....
相当于
[root@centos ~]# awk -F: ‘{print $1,$3}‘ /etc/passwd
输出字段分隔符,默认为空白字符
[root@centos ~]# awk -v FS=: -v OFS=‘---------‘ ‘{print $1,$3}‘ /etc/passwd
root---------0
bin---------1
daemon---------2
adm---------3
lp---------4
sync---------5
shutdown---------6
halt---------7
....
输入记录分隔符,指定输入时的换行符
[root@centos ~]# cat awk.txt
a,b,c;1,2,3;aa,dd,cc
zz,yy,ww;444,555,6663;AA
BB,CC
[root@centos ~]# awk -v FS="," -v RS=";" ‘{print $1}‘ awk.txt
a
1
aa
444
AA
BB
输出记录分隔符,输出时用指定符号代替换行符
[root@centos ~]# awk -v FS="," -v RS=";" -v ORS=‘-------‘ ‘{print $1}‘ awk.txt
a-------1-------aa-------444-------AA
BB-------
字段数量
[root@centos ~]# awk -F: ‘{print NF}‘ awk.txt #awk引用变量时,变量前不需要加$
1
1
1
[root@centos ~]# awk -F, ‘{print NF}‘ awk.txt
7
5
2
[root@centos ~]# awk -F, ‘{print $(NF-1)}‘ awk.txt
dd
555
BB
记录号
统计/etc/passwd文件里每行对应的用户名
[root@centos ~]# awk -F: -v OFS=‘----------‘ ‘{print NR,$1}‘ /etc/passwd
1----------root
2----------bin
3----------daemon
4----------adm
5----------lp
6----------sync
7----------shutdown
8----------halt
9----------mail
10----------operator
....
多个文件行数合并计数
[root@centos ~]# awk ‘{print NR}‘ /etc/fstab /etc/issue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
多个文件单个计数
[root@centos ~]# awk ‘{print FNR}‘ /etc/fstab /etc/issue
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
[root@centos ~]# awk ‘{print FILENAME}‘ /etc/fstab /etc/issue
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/issue
/etc/issue
/etc/issue
/etc/issue
[root@centos ~]# awk ‘BEGIN{print ARGC}‘ /etc/fstab /etc/issue
3
[root@centos ~]# awk ‘BEGIN{print ARGV[0]}‘ /etc/fstab /etc/issue
awk
[root@centos ~]# awk ‘BEGIN{print ARGV[1]}‘ /etc/fstab /etc/issue
/etc/fstab
[root@centos ~]# awk ‘BEGIN{print ARGV[2]}‘ /etc/fstab /etc/issue
/etc/issue
[root@centos ~]# awk -F: ‘{title="CEO";print title":"$1}‘ /etc/passwd
CEO:root
CEO:bin
CEO:daemon
CEO:adm
CEO:lp
CEO:sync
CEO:shutdown
CEO:halt
....
printf “FORMAT” , item1, item2, ...
1. 必须制定FORMAT
2. 不会自动换行,需要显式给出换行控制符,\n
3. FORMAT中需要分别为后面每个item指定格式符
%c:显示字符的ASCII码
%d, %i:显示十进制整数
%e, %E:显示科学计数法数值
%f:显示为浮点数
%g, %G:以科学计数法或浮点形式显示数值
%s:显示字符串
%u:无符号整数
%%:显示%自身
以分号为分隔符,取第一段字符
[root@centos ~]# awk -F: ‘{printf "%s\n",$1}‘ /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp
nobody
....
#[.#] 第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f
- 左对齐(默认右对齐) %-15s
+ 显示数值的正负符号 %+d
取小数点后精度
[root@centos ~]# awk ‘BEGIN{srand();printf "%.1f",rand()}‘
0.5
[root@centos ~]# awk ‘BEGIN{srand();printf "%.2f",rand()}‘
0.05
[root@centos ~]# awk ‘BEGIN{srand();printf "%.3f",rand()}‘
0.799
添加注释,并控制其显示格式
[root@centos ~]# awk -F: ‘BEGIN{print "Usernamem UID"}{printf "%-15s %5d\n",$1,$3}‘ /etc/passwd | head
Usernamem UID
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
x+y, x-y, x*y, x/y, x^y, x%y
- x:转换为负数
+x:将字符串转换为数值
字符串连接,没有符号的操作符
=, +=, -=, *=, /=, %=, ^=,++, --
主要观察i++,++i的区别
[root@centos ~]# awk ‘BEGIN{i=0;print i++,i}‘
0 1
[root@centos ~]# awk ‘BEGIN{i=0;print ++i,i}‘
1 1
==, !=, >, >=, <, <=
以":"为分隔符,匹配第三段数值为0的行
[root@centos ~]# awk -F: ‘$3==0‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash
~:左边是否和右边匹配,包含
!~:是否不匹配
$0代表了文件里的全部内容,在这里表示不匹配以"#"开头的行
[root@centos ~]# awk ‘$0 !~ /^#/‘ /etc/fstab
UUID=66002ce1-278d-4845-b822-79b86c947af8 / xfs defaults 0 0
UUID=a2c11cbb-6d9d-4a63-b961-a4d57c4c85c9 /boot xfs defaults 0 0
UUID=9043785a-2496-4966-8eb6-2959d7d943ce swap swap defaults 0 0
/dev/sr0 /media/cdrom iso9660 defaults 0 0
这里表示匹配"#"开头的行
[root@centos ~]# awk ‘$0 ~ /^#/‘ /etc/fstab
#
# /etc/fstab
# Created by anaconda on Tue Mar 5 20:52:08 2019
#
# Accessible filesystems, by reference, are maintained under ‘/dev/disk‘
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
与&&,或||,非!
这里表示不匹配以"#"和空行的行
[root@centos ~]# awk ‘$0 !~ /^#/ && $0 !~ /^$/‘ /etc/fstab
UUID=66002ce1-278d-4845-b822-79b86c947af8 / xfs defaults 0 0
UUID=a2c11cbb-6d9d-4a63-b961-a4d57c4c85c9 /boot xfs defaults 0 0
UUID=9043785a-2496-4966-8eb6-2959d7d943ce swap swap defaults 0 0
/dev/sr0 /media/cdrom iso9660 defaults 0 0
以":"为分隔符,取第三段为0或者>=1000的行
[root@centos ~]# awk -F: ‘$3==0 || $3>=1000‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
dxy:x:1000:1000:dxy:/home/dxy:/bin/bash
以":"为分隔符,取第三段非大于10的行
[root@centos ~]# awk -F: ‘!($3>=10)‘ /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:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
selector?if-true-expression:if-false-expression
以":"作为分隔符,当第三段数值>=1000时输出"system user:用户名 uid值",否则输出"common user:用户名 uid值"
[root@centos ~]# awk -F: ‘$3>=1000?user="common user":user="system user"{printf "%s: %-20s %5d\n",user,$1,$3}‘ passwd.txt
system user: root 0
common user: bin 1000
system user: daemon 2
common user: nfsnobody 65534
system user: adm 3
common user: lp 1040
system user: sync 5
system user: shutdown 6
system user: halt 7
common user: dxy 1000
system user: mail 8
system user: operator 11
根据pattern条件,过滤匹配的行,再做处理
1. 如果未指定:空模式,匹配每一行
2. /regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来
awk ‘/^UUID/{print $1}‘ /etc/fstab
awk ‘!/^UUID/{print $1}‘ /etc/fstab
3. relational expression: 关系表达式,结果为“真”才会被处理
真:结果为非0值,非空字符串
假:结果为空字符串或0值
4. line ranges:行范围
startline,endline:/pat1/,/pat2/ 不支持直接给出数字格式
5. BEGIN/END模式
BEGIN{}:仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次
再pattern中,如果未指定条件,即空模式,则匹配到每一行
[root@centos ~]# awk -F: ‘i=1;j=1{print i,j}‘ passwd.txt
root:x:0:0:root:/root:/bin/bash
1 1
bin:x:1000:1000:bin:/bin:/sbin/nologin
1 1
daemon:x:2:2:daemon:/sbin:/sbin/nologin
1 1
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
1 1
adm:x:3:4:adm:/var/adm:/sbin/nologin
1 1
lp:x:1040:1070:lp:/var/spool/lpd:/sbin/nologin
1 1
sync:x:5:0:sync:/sbin:/bin/sync
1 1
....
匹配存在字符串"root"的行
[root@centos ~]# awk ‘/root/‘ passwd.txt
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
匹配以字符串"root"开头的行
[root@centos ~]# awk ‘/^root/‘ passwd.txt
root:x:0:0:root:/root:/bin/bash
匹配最后一个字段为"/bin/bash"的行
[root@centos ~]# awk -F: ‘$NF=="/bin/bash"‘ passwd.txt
root:x:0:0:root:/root:/bin/bash
dxy:x:1000:1000:dxy:/home/dxy:/bin/bash
匹配最后一个字段以"/bash"结尾的行的第一个字段
[root@centos ~]# awk -F: ‘$NF ~ /bash$/{print $1}‘ passwd.txt
root
dxy
在关系表达式中,结果为"真"输出非空字符串,结果为"假"输出空字符串或0值
[root@centos ~]# awk ‘!0‘ passwd.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1000:1000:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/....
[root@centos ~]# awk ‘!1‘ passwd.txt
匹配以"root"的行和以"nobady"开头的行之间所有的内容
[root@centos ~]# awk -F: ‘/^root\>/,/^nobody\>/‘ /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:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
匹配第10行至第20行之间的行的第一个字段
[root@centos ~]# awk -F: ‘(NR>=10&&NR<=20){print NR,$1}‘ /etc/passwd
10 operator
11 games
12 ftp
13 nobody
14 systemd-network
15 dbus
16 polkitd
17 libstoragemgmt
18 colord
19 rpc
20 gluster
BEGIN/END模式:BEGIN文本处理开始之前执行一次,END文本处理完成之后执行一次
[root@centos ~]# awk -F: ‘BEGIN{print " USER UID \n--------------- "}{print $1,$3} END{print "=============="}‘ passwd.txt
USER UID
---------------
root 0
bin 1000
daemon 2
nfsnobody 65534
adm 3
lp 1040
sync 5
shutdown 6
halt 7
dxy 1000
mail 8
operator 11
==============
语法
if(condition){statement;…}[else statement]
if(condition1){statement1}else if(condition2){statement2}else{statement3}
使用场景
对awk取得的整行或某个字段做条件判断
判断第三个字段是否>=1000,如果符合条件则print输出第一,三字段的内容
[root@centos ~]# awk -F: ‘{if($3>=1000)print $1,$3}‘ /etc/passwd
nfsnobody 65534
dxy 1000
定义test变量,判断test值,>=90输出“very good”,90>=test>=60输出“good”,<=60时输出“no good”
[root@centos ~]# awk ‘BEGIN{test=80;if(test>=90)print "very good";else if(test>=60)print "good";else print "no good"}‘
good
[root@centos ~]# awk ‘BEGIN{test=90;if(test>=90)print "very good";else if(test>=60)print "good";else print "no good"}‘
very good
[root@centos ~]# awk ‘BEGIN{test=50;if(test>=90)print "very good";else if(test>=60)print "good";else print "no good"}‘
no good
语法
while(condition){statement;…}
条件“真”,进入循环;条件“假”,退出循环
使用场景
对一行内的多个字段逐一类似处理时使用
对数组中的各元素逐一处理时使用
输出符合条件的行
[root@centos ~]# awk ‘/^[[:space:]]*linux16/‘ /boot/grub2/grub.cfg
linux16 /vmlinuz-3.10.0-957.el7.x86_64 root=UUID=66002ce1-278d-4845-b822-79b86c947af8 ro rhgb quiet
默认以空格作为分隔符,输出字段,以及字段的长度
[root@centos ~]# awk ‘/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i); i++}}‘ /etc/grub2.cfg
linux16 7
/vmlinuz-3.10.0-957.el7.x86_64 30
root=UUID=66002ce1-278d-4845-b822-79b86c947af8 46
ro 2
rhgb 4
quiet 5
语法
do {statement;…}while(condition)
意义
无论真假,至少执行一次循环体
[root@centos ~]# awk ‘BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);print total}‘
5050
语法
for(expr1;expr2;expr3) {statement;…}
特殊用法:能够遍历数组中的元素
语法:for(var in array) {for-body}
默认以空格作为分隔符,输出字段,以及字段的长度
[root@centos ~]# awk ‘/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}‘ /boot/grub2/grub.cfg
linux16 7
/vmlinuz-3.10.0-957.el7.x86_64 30
root=UUID=66002ce1-278d-4845-b822-79b86c947af8 46
ro 2
rhgb 4
quiet 5
语法
switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2; ...; default: statementn}
[root@centos ~]# awk ‘BEGIN{sum=0;for(i=1;i<=100;i++){sum+=i} print sum}‘
5050
[root@centos ~]# awk ‘BEGIN{sum=0;for(i=1;i<=100;i++) {if(i%2==0)break;sum+=i}print sum}‘
1
[root@centos ~]# awk ‘BEGIN{sum=0;for(i=1;i<=100;i++) {if(i%2==0)continue;sum+=i}print sum}‘
2500
[root@centos ~]# awk -F: ‘{if($3%2!=0) next; print $1,$3}‘ /etc/passwd
root 0
daemon 2
lp 4
shutdown 6
mail 8
games 12
ftp 14
systemd-network 192
libstoragemgmt 998
rpc 32
gluster 996
....
index-expression:
1. 可使用任意字符串;字符串要使用双引号括起来
2. 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”
3. 若要判断数组中是否存在某元素,要使用“index in array” 格式进行遍历
[root@centos ~]# awk ‘BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}‘
Monday
语法:
for(var in array) {for-body}
var会遍历array的每个索引
[root@centos ~]# awk ‘BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays){print weekdays[i]}}‘
Tuesday
Monday
rand():返回0和1之间一个随机数
[root@centos ~]# awk ‘BEGIN{for(i=1;i<=10;i++)print rand()}‘
0.237788
0.291066
0.845814
0.152208
0.585537
0.193475
0.810623
0.173531
0.484983
0.151863
length([s]):返回指定字符串的长度
[root@centos ~]# echo ${a[@]}
Mon Tur Week
[root@centos ~]# echo ${a[@]} | awk ‘{print length($0)}‘
12
[root@centos ~]# echo ${a[@]} | awk ‘{print length($1)}‘
3
[root@centos ~]# echo ${a[@]} | awk ‘{print length($2)}‘
3
[root@centos ~]# echo ${a[@]} | awk ‘{print length($3)}‘
4
sub(r,s,[t]):对t字符串搜索r表示模式匹配的内容,并将第一个匹配内容替换为s
[root@centos ~]# echo "2008:08:08 08:08:08" | awk ‘sub(/:/,"-",$1)‘
2008-08:08 08:08:08
gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容
[root@centos ~]# echo "2008:08:08 08:08:08" | awk ‘gsub(/:/,"-",$0)‘
2008-08-08 08-08-08
split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中,第一个索引值为1,第二个索引值为2,…
[root@centos ~]# awk ‘BEGIN{time="2008:08:08 08:08:08";split(time,array,":");for(i in array){print i,array[i];}}‘
4 08
5 08
1 2008
2 08
3 08 08
for…in 输出,因为数组是关联数组,默认是无序的。所以通过for…in 得到是无序的数组。如果需要得到有序数组,需要通过下标获得
[root@centos ~]# awk ‘BEGIN{time="2008:08:08 08:08:08";lens=split(time,array,":");for(i=1;i<=lens;i++){print i,array[i];}}‘
1 2008
2 08
3 08 08
4 08
5 08
function name ( parameter, parameter, ... ) {
statements
return expression
}
[root@centos ~]# chmod +x fun.awk #写完awk程序文件要加上执行权限
[root@centos ~]# cat fun.awk
function max(x,y){
x>y?var=x:var=y
return var
}
BEGIN{a=3;b=6;print max(a,b)}
[root@centos ~]# awk -f fun.awk #awk -f 引用awk函数程序文件
6
格式:
awkfile var=value var2=value2... Inputfile
在BEGIN过程中不可用。直到首行输入完成以后,变量才可用。可以通过-v 参数,让awk在执行BEGIN之前得到变量的值。命令行中每一个指定的变量都需要一个-v参数
[root@centos ~]# cat fun.awk
#!/bin/awk -f
function max(x,y){
x>y?var=x:var=y
return var
}
BEGIN{print max(a,b)}
[root@centos ~]# awk -v a=10 -v b=20 -f fun.awk
20
[root@centos ~]# awk -v a=100 -v b=20 -f fun.awk
100
空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了awk的变量外其他一律用""引用起来
awk调用shell命令
[root@centos ~]# awk ‘BEGIN{system("hostname")}‘
centos.magedu36.com
[root@centos ~]# awk ‘BEGIN{system("ls")}‘
a anaconda-ks.cfg awk.txt Documents fun.awk Music Pictures Templates Videos
aaa a.sh Desktop Downloads initial-setup-ks.cfg passwd.txt Public test.txt
awk调用变量
[root@centos ~]# awk ‘BEGIN{name="Darius";system("echo My name is " name)}‘
My name is Darius
[root@centos ~]# awk ‘BEGIN{score=100;system("echo Your score is " score)}‘
Your score is 100
vim deny_dos.sh
while true ;do
awk ‘/^[0-9]/{IP[$1]++}END{for(i in IP){if (IP[i]>=100)print i}}‘ /var/log/httpd/access_log | while read line;do iptables -A INPUT -s $line -j
REJECT;done
sleep 300
done
1 blog.magedu.com
2 www.magedu.com
…
999 study.magedu.com
awk -F‘[" ".]‘ ‘{print $2}‘ ip_list.txt >> ip_list.txt
[root@centos ~]# awk ‘/^[UUID\/]/{fs[$3]++}END{for(i in fs){print i,fs[i]}}‘ /etc/fstab
swap 1
xfs 2
iso9660 1
标签:music 报告 common continue 特殊用法 switch语句 ati ks.cfg 文本处理三剑客
原文地址:https://blog.51cto.com/12980155/2378250