GNU AWK

awk

awk官方给出的是 pattern scanning and processing language即模式扫描处理语言,我们CentOS一般用的是GNU AWK,官方给出的语法有五种,我们只举例前两种使用格式,下面是语法:

   gawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...
   gawk [ POSIX or GNU style options ] [ -- ] program-text file ...

   pgawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...
   pgawk [ POSIX or GNU style options ] [ -- ] program-text file ...

   dgawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...

语法

gawk [ POSIX or GNU style options ] [ – ] program-text file …

  • -F 指定分隔符;
  • -v var=value 赋值变量,使AWK处理过程中可以调用
* -v 表示变量
FS:输入字段分隔符,默认空白字符为分隔符
awk -v FS=':' '{print $1,FS,$3}’ /etc/passwd
awk –F: '{print $1,$3,$7}’ /etc/passwd

OFS:输出字段分隔符,默认为空白字符,使用,号进行使用,也可以命令内部使用OFS的变量
awk -v FS=‘:’ -v OFS=‘:’ '{print $1,$3}’ /etc/passwd
awk -v FS=":" -v OFS=": " '{print $1OFS$3}' /etc/passwd


RS:输入记录分隔符,指定输入时的换行符,原换行符仍有效
[root@localhost ~]#awk -v RS=" " '{print NR,$0}' /root/f1.test
1 aaa
2 bbb
3 ccc
abcd
4 bcd
5 cd
efi
tge
slk
[root@localhost ~]#cat f1.test
aaa bbb ccc
abcd bcd cd
efi
tge
slk
[root@localhost ~]#     

ORS:输出记录分隔符,输出时用指定符号代替换行符

awk  -v ORS='###'‘{print }’ /root/f1.test
1 aaa bbb ccc###2 abcd bcd cd###3 efi###4 tge###5 slk###[root@localhost ~]#

NF:字段数量
awk -F: ‘{print NF}’ /etc/fstab,引用内置变量不用$ 显示每行的列数
awk -F: '{print $(NF-1)}' /etc/passwd    打印出倒数第二个字段
awk -F: '{print $NF}'/etc/passwd 打印最后一个字段

NR:行号
awk '{print NR}' /etc/fstab ; awk END'{print NR}' /etc/fstab

FNR:各文件分别计数,行号
awk '{print FNR}' /etc/fstab /etc/inittab

FILENAME:当前文件名
awk '{print FILENAME}’ /etc/fstab
[root@localhost ~]#awk '{print FILENAME}' /etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
ARGC:命令行参数的个数
awk '{print ARGC}’ /etc/fstab /etc/inittab
命令本身也是参数的个数
awk ‘BEGIN {print ARGC}’ /etc/fstab /etc/inittab
ARGV:数组,保存的是命令行所给定的各参数
awk ‘BEGIN {print ARGV[0]}’ /etc/fstab  /etc/inittab
awk ‘BEGIN {print ARGV[1]}’ /etc/fstab /etc/initt
{print ARGV[ARGC-1]}
BEGIN和END
BEGIN:模式指定了处理文本之前需要执行的操作
END   :模式指定了处理完所有行后执行的操作

-f scripfile 从脚本文件中读取awk命令

   awk -F: -f awk.txt /etc/passwd
   awk.txt
   {print $1,$3}
格式化输出printf:

printf 必须指定FORMAT,而且不会自动换行,如需换行需在FORMAT内添加 \n,FORMAT中需要分别为后面每个item指定格式符
格式符

%c    : 显示字符的ASCII码
%i和%d: 显示十进制整数
%e和%E: 显示科学计数法数值
%f    : 显示小数点
%g和%G: 以科学计算法显示数值
%s    :显示字符串
%u    :无符号整数
%%    : 显示%号自身

修饰符

#[.#] : 第一个数显示正数位数;第二个#表示小数点精度 如%3.1f
-     : 左对齐 如:%-15s  (默认是右对齐)
+     : 显示数值的正负符号 %+d

我们结合BEGIN 和格式符,修饰符进行语法使用

[root@localhost ~]#awk -F: 'BEGIN{print "user:--------------------UID:----------------------\n"}{printf "%-23s %-25d \n",$1,$3}' /etc/passwd 
user:--------------------UID:----------------------

root                    0                         
bin                     1                         
daemon                  2                         
adm                     3                         
lp                      4    
[root@localhost ~]#awk -F: 'BEGIN{print "user:--------------------UID:----------------------\n"}{printf "%-23s %25d \n",$1,$3}END{print "END结尾看看而己"}' /etc/passwd 
user:--------------------UID:----------------------

root                                            0 
bin                                             1 
daemon                                          2 
adm                                             3     
...
zhang                                        1000 
apache                                         48 
END结尾看看而己

当我们结合着一起使用时是不是感觉出来了,BEGIN的作用是在awk进行脚本内行间循环处理之前进行操作的,我们也可以在之后加END{语法}进行循环后的操作.

—这里注意一点,当printf使用时 必须指定 FORMAT

[root@localhost ~]#awk -F: 'BEGIN{print "user:--------------------UID:----------------------\n"}{printf "%-23 %25 \n",$1,$3}END{print "END结尾看看而己"}' /etc/passwd  
user:--------------------UID:----------------------
%25 
%25 
%25 
%25 
位置变量:

$0 , $1 这些在awk不是指的参数,而是指的awk执行操作时每行进行处理的列,$1表示第1列, 2... 0表示所有列即整行
如:

[root@localhost ~]#awk -F: '{print $1,$2,$3}END{print $0}' /etc/passwd
root x 0
bin x 1
daemon x 2
adm x 3
...
apache x 48
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
匹配模式
1.如果匹配模式为空,则表示匹配每一行
2./regular expression/
例如:

 仅处理只匹配到的行

         [root@CentOS ~]# awk -F: '\$NF~/bash\$/{print \$1,\$NF}' /etc/passwd 
         root /bin/bash
3.关系表达式;结果有真有假,当为真时才会被处理
如:
4.行范围 /pat1/,/pat2/
5.BEGIN/END模式
BEGIN{}: 仅在开始处理文件中的文本之前执行一次
END{} 仅在结束处理文件后文件之后执行一次

[root@localhost ~]#awk -F: '($3>=2&&$3<=10){print $1,$3}' /etc/passwd    
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
常用的action

Expressions —表达式
Contronl Statements : if , while , for 等控制语句
Compound statements : 组合语句
input statements 输入语句
output statments 输出语句

操作符

算术运算操作符

x+y , x-y , x*y , x/y , x^y , x%y ,-x , +y

赋值操作符

 = , +=  ,  -=  ,  /=  ,  %=  ,  ^=  ,  ++  ,  --

比较操作符

\> , >= , < , <= , != , ==

模式匹配符

~:  是否匹配
!~: 是否不匹配

逻辑操作符

&& : 与   在awk中表示必须满足与的两个条件
 | |   : 或
 ! :非
控制语句
if(condition){statements}
if(condition)statements else{statement}
while(conditon){statements}
do {statements} while(conditon)
for(expr1;expr2;expr3){statements}
break continue exit
array [index] 

单分支if判断例子: if (condition){statements}

[root@localhost ~]#awk -F: '{if($3>=500)print $1,$3}' /etc/passwd   判断打印出uid大于等于500的账号和UID
systemd-bus-proxy 999
polkitd 998
unbound 997
libstoragemgmt 996
colord 995
saslauth 994
geoclue 993
nfsnobody 65534
chrony 992
setroubleshoot 991
gnome-initial-setup 990
zhang 1000

多分支if判断列子:if(condition) else{statements}

[root@localhost ~]#awk -F: '{if($3>=1000){printf "普通用户:%-25s\n",$1}else{printf "系统用户: %-25s\n",$1}}' /etc/passwd
系统用户: root                     
系统用户: bin                      
系统用户: daemon                   
系统用户: adm       
...               
普通用户:zhang                    
系统用户: apache   

while循环例子:while(condition)statement
依次显示grub2.cfg以空白字符开头中间任间包含linux16的行的列,并打印出列和列长

[root@localhost ~]#awk  '/^[[:space:]]*linux16/{i=1;while(i<=NF){print $i,length($i);i++}}' /etc/grub2.cfg       
linux16 7
/vmlinuz-3.10.0-514.el7.x86_64 30
root=UUID=241b7f92-047c-4d85-b0b3-2be915811ed5 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
LANG=en_US.UTF-8 16
linux16 7
/vmlinuz-0-rescue-42b6aa44a83f48efa5f14aeb1eb12c90 50
root=UUID=241b7f92-047c-4d85-b0b3-2be915811ed5 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5

我们使用for语句编写上面的例子for(expr1;expr2;expr3){statements}

[root@localhost ~]#awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++)print $i,length($i)}' /etc/grub2.cfg  
linux16 7
/vmlinuz-3.10.0-514.el7.x86_64 30
root=UUID=241b7f92-047c-4d85-b0b3-2be915811ed5 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
LANG=en_US.UTF-8 16
linux16 7
/vmlinuz-0-rescue-42b6aa44a83f48efa5f14aeb1eb12c90 50
root=UUID=241b7f92-047c-4d85-b0b3-2be915811ed5 46
ro 2
crashkernel=auto 16
rhgb 4

next
能提前结束对本行的处理,提前进入下次循环;
例:

判断uid余2不等于0的次提前结束行处理和打印等于0的账号和UID
[root@localhost ~]#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
polkitd 998
libstoragemgmt 996
关联数组

array[index-expression]

1. 可使用任意字符串;字符串要使用双引号
2. 如果某数组元素事先不存在,在引用时awk会自动创建此元素,为将其值初始化为“空串”;

[root@localhost ~]#awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}'
Monday
[root@localhost ~]#awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["tue"]}'
Tuesday
3.如要遍历数组中的每个元素,要使用for循环 for (var in array ){for-body}

[root@localhost ~]#awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays){print weekdays[i]}}'    
Tuesday
Monday

使用数组例子1:查看端口状态及统计

[root@localhost ~]#netstat -tan |awk '/tcp\>/{i[$NF]++}END{for(j in i)print j,i[j]}'
LISTEN 5
ESTABLISHED 1
[root@localhost ~]#

例子2:计算/etc/fstab内每行单词出现的次数

[root@localhost ~]#awk '{i=1;while(i<=NF){j[$i]++;i++}}END{for(i in j)print i,j[i]}' /etc/fstab     
man 1
and/or 1
UUID=17e5a40c-1872-45ce-807e-b196a3e299b2 1
maintained 1
xfs 3
15 1
Accessible 1
# 7
are 1
defaults 4
blkid(8) 1
/ 1
0 8
See 1
Sat 1
UUID=af4aacb5-abf4-4113-b19b-0542229824f1 1
Created 1
on 1
mount(8) 1
anaconda 1
fstab(5), 1
19:44:18 1
/app 1
/boot 1
UUID=a3e1d352-4dc8-4124-857c-367cecd5a86b 1
findfs(8), 1
2017 1
UUID=241b7f92-047c-4d85-b0b3-2be915811ed5 1
'/dev/disk' 1
by 2
/etc/fstab 1
pages 1
more 1
info 1
swap 2
Jul 1
filesystems, 1
reference, 1
for 1
under 1
[root@localhost ~]#

使用for语句
[root@localhost ~]#awk '{for(i=1;i<=NF;i++)j[$i]++}END{for(i in j)print i,j[i]}' /etc/fstab
man 1
and/or 1
UUID=17e5a40c-1872-45ce-807e-b196a3e299b2 1
maintained 1
xfs 3
15 1
Accessible 1
# 7
are 1
defaults 4
blkid(8) 1
/ 1
0 8
See 1
Sat 1
UUID=af4aacb5-abf4-4113-b19b-0542229824f1 1
Created 1
on 1
mount(8) 1
anaconda 1
fstab(5), 1
19:44:18 1
/app 1
/boot 1
UUID=a3e1d352-4dc8-4124-857c-367cecd5a86b 1
findfs(8), 1
2017 1
UUID=241b7f92-047c-4d85-b0b3-2be915811ed5 1
'/dev/disk' 1
by 2
/etc/fstab 1
pages 1
more 1
info 1
swap 2
Jul 1
filesystems, 1
reference, 1
for 1
under 1

数组切片

例: 查看本地访问IP的次数 使用了数组切片

[root@localhost ~]#netstat -tan|awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}'
192.168.3.1 1
0.0.0.0 5
[root@localhost ~]#netstat -tan|awk '/^tcp\>/{split($5,ip,":");count[ip[2]]++}END{for(i in count){print i,count[i]}}' 
* 5
52563 1
[root@localhost ~]#netstat -tan|awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}' 
192.168.3.1 1
0.0.0.0 5
[root@localhost ~]#
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值