Linux-awk

一· awk简介

awk是一门编程语言,用于处理文本,可以处理来自标准输入、或多个文件、或来自其他程序输出的文本。支持用户自定义函数和正则表达式。
处理文本的方式:他逐行扫描,寻找匹配正则表达式的行,并在行上执行指定操作,如果没有指定操作,则把所有匹配的行输出到屏幕。如果没有指定匹配模式则操作所有行。

二. awk的语法格式

awk [options] ‘command’ filenames
awk [options] -f awk-script-file filenames

三. awk的选项

-F : 定义输入字符分隔符,默认是空格或tab

四. awk的命令

BEGIN{} {} END{}
行处理前 行处理 行处理后

在这里插入图片描述

[root@localhost ~]# cat test.txt 
111
222
333
[root@localhost ~]# awk 'BEGIN{print 1/2} {print "ok"} END{print "---"}' test.txt 
0.5
ok
ok
ok
---
[root@localhost ~]# 

BEGIN{}通常用于定义变量,如
BEGIN{FS=":";OFS="\t"}

五. awk的命令格式

awk ‘pattern’ filename

# 匹配pattern的行将整行输出,没匹配的行不输出
[root@localhost ~]# awk '/root/' passwd 
root:x:0:0:root:/root:/bin/bash

awk ‘{action}’ filename

# 按照action处理所有行
[root@localhost ~]# awk -F":" '{print $1}' passwd 
root
bin
daemon

awk ‘pattern {action}’ filename

# 只对匹配的行按照action处理
[root@localhost ~]# awk -F":" '/root/{print $2}' passwd 
x

command | awk ‘pattern {action}’

[root@localhost ~]# df -P | grep '/' |awk '$4 > 8129256 {print $4}'
41888252

六. awk的工作原理

  1. awk用一行作为输入,并将这一行赋给内部变量$0, 每一行也可以称作一个记录,以换行符结束;
  2. 然后,行被(默认为空格或制表符)分解成字段,每个字段存储在已编号的变量中,从$1开始,多达100个字段;
  3. awk是如何知道用空格来分割字段呢?是因为有一个内部变量FS来确定字段分隔符,初始时FS为空格;
  4. awk打印字段时,将已设置的方式使用print函数打印,awk在打印的字段间加上空格,是因为$1和$2之间有逗号,逗号被映射为另一个内部变量,称为输出字段分隔符OFS,OFS默认为空格;
  5. awk输出之后,将从文件中获取下一行,并将其存储在变量$0中覆盖原来内容。

七. awk的内部变量

$0: 保存当前记录的内容
NR:记录的编号,如果同时处理多个文件,编号延续
FNR:记录的编号,如果同时处理多个文件,编号将重新开始
NF:记录中有几个字段

[root@localhost ~]# awk -F":" '{print $0,NF}' passwd 
root:x:0:0:root:/root:/bin/bash 7
bin:x:1:1:bin:/bin:/sbin/nologin 7
daemon:x:2:2:daemon:/sbin:/sbin/nologin 7

FS:输入字段分隔符,默认为空格和tab

# 可以使用多个符号同时当做FS,利用用空格、tab和冒号
[root@localhost ~]# awk -F "[ \t:]" '{print $2}' test.txt 
[root@localhost ~]# awk  'BEGIN{FS="[ \t:]"} {print $2}' test.txt 

OFS:输出字段分隔符
RS:输入记录分隔符,默认为换行

[root@localhost ~]# cat test.txt 
1:2:3:4 a:b:c:d
q:w:e:r 5:4:3:2
[root@localhost ~]# awk -F":" 'BEGIN{RS=" "} {print$1,$2}' test.txt 
1 2
a b
5 4

ORS:输出记录分隔符,默认为换行

八. awk的两个打印函数print和printf

  1. print
awk 'BEGIN{FS=":";print"开始了"} {print"用户名:" $1 "\t用户ID:" $3} END{print"结束了"}' /etc/passwd
  1. printf用于格式化输出
%s  字符类型
%d  数值类型
%f   浮点数值类型

15  占15个字符

-    表示左对齐,默认是右对齐

printf默认不会在行末打印换行,需要自己加\n
[root@localhost ~]# awk 'BEGIN{FS=":";print"开始了"} {printf"用户名:%-20sID:%-15s\n", $1,$3} END{print"结束了"}' /etc/passwd
开始了
用户名:root                ID:0              
用户名:bin                 ID:1              
用户名:daemon              ID:2              
用户名:adm                 ID:3              
用户名:lp                  ID:4              
用户名:sync                ID:5              
用户名:shutdown            ID:6  

九 awk的command包括模式和动作两部分

# 任何awk语句都由模式和动作组成;
# 模式决定动作语句何时触发,以及触发事件;
# 动作是对数据进行的操作;
# 动作放着花括号中{}
# 如果省略模式部分,动作将保持时刻执行状态:
#  模式可以是任何条件语句或复合语句或正则表达式
# BEGIN和END是两个特色的模式
# BEGIN语句用于设置计数和打印头;BEGIN语句用于行数据处理之前
# END语句用于行数据处理之后,打印行总数和结尾状态

十 awk的模式

10.1 模式为正则表达式

# 整行匹配
## 在整行中匹配某个正则表达式时可以直接写正则表达式;也可以用$0~后再跟正则表达式
### 直接用正则表达式就是在整行做匹配
[root@localhost ~]# awk '/^andy/' /etc/passwd
andy:x:1000:1000:andy:/home/andy:/bin/bash
### 正则表达式前跟$0~也是在整行匹配正则表达式
[root@localhost ~]# awk '$0~/^andy/' /etc/passwd
andy:x:1000:1000:andy:/home/andy:/bin/bash
### 后面没有动作或动作为print$0都是整行打印的意思
[root@localhost ~]# awk '/^andy/{print $0}' /etc/passwd
andy:x:1000:1000:andy:/home/andy:/bin/bash
# !接正则表达式或!~接正则表达式都是取反的意思
[root@localhost ~]# awk '!/^andy/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@localhost ~]# awk '$0!~/^andy/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
# 字段匹配正则表达式
[root@localhost ~]# awk -F":" '$5~/andy/' /etc/passwd
andy:x:1000:1000:andy:/home/andy:/bin/bash
[root@localhost ~]# awk -F":" '$5!~/andy/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin

10.2 模式为比较表达式

比较表达式对文本进行比较,只有当条件为真时,才执行指定的动作;
比较表达式使用关系运算符来比较数字或字符串。

 关系运算符:
 运算符		含义			示例
 <				小于			a<b
 <=
 ==
 !=
 >=
 >
[root@localhost ~]# awk -F":" '$3>999' /etc/passwd
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
andy:x:1000:1000:andy:/home/andy:/bin/bash

[root@localhost ~]# awk -F":" '$3==0{print $1}' /etc/passwd
root

[root@localhost ~]# awk -F":" '$NF=="/bin/bash"{print $1}' /etc/passwd
root
andy

10.3 模式为条件表达式

awk ‘{if(条件表达式) {动作}}’
awk ‘{if(条件表达式) {动作1} else {动作2}}’

[root@localhost ~]# awk -F":" '$3==0 {print $1}' /etc/passwd
root
# 动作可以加花括号也可不加
[root@localhost ~]# awk -F":" '{if($3==0) {print $1}}' /etc/passwd
root
[root@localhost ~]# awk -F":" '{if($3==0) print $1}' /etc/passwd
root

10.4 模式中可以执行计算

算术表达式:±*/%^
awk都是按照浮点数方式来执行算术运算的

 awk -F":" '$3*2>999' /etc/passwd
 awk -F":" '{if($3*2>999){print $1}}' /etc/passwd

10.5 模式使用逻辑操作符和复合模式

&& 		逻辑与		a&&b
||		逻辑或		a||b
!		逻辑非		!a
[root@localhost ~]# awk -F":" '$7=="/bin/bash" && $3 > 999' /etc/passwd
andy:x:1000:1000:andy:/home/andy:/bin/bash

10.6 范围模式

awk范围模式先匹配从第一个模式的首次匹配的行到第二个模式的首次匹配的行之间的所有行;然后从下一行再次匹配从第一个模式正则表达式,如果匹配了就再匹配第二个模式,然后取这次两个匹配之间的所有行;以此类推。如果匹配到第一个模式而没有发现第二个模式, awk 就将显示从第一个模式首次出现的行到文件末尾之间的所有行。

[root@localhost ~]# awk -F":" '$1~/root/,$1~/lp/' /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

10.7 在比较表达式中,可以用.加数字表示零点几;在动作语句中可以把字段类型为数值类型的字段直接算术运算

# 将第二字段的值大于0.8的直接加10打印出来
[root@localhost ~]# cat test.txt 
121	0.1	0.9	33
23	0.8	2323	34
23	0.9	sdf	sdf

[root@localhost ~]# awk '$2>.8{print $2+10}' test.txt 
10.9
[root@localhost ~]# awk '$2>.8{print $2-.2}' test.txt 
0.7

10.8 动作中可以使用三目运算表达式来代替if else

三目运算表达式: a?b:c
如果条件表达式a成立,则三目运算表达式的值为b;
如果条件表达式a不成立,则三目运算表达式的值为c

[root@localhost ~]# cat test.txt 
121	0.1	0.9	33
23	0.8	2323	34
23	0.9	sdf	sdf
[root@localhost ~]# awk '{print ($1>23? "第一个字段的值大于23:"$1 : "第一个字段的值小于23:"$1)}' test.txt 
第一个字段的值大于23:121
第一个字段的值小于23:23
第一个字段的值小于23:23

[root@localhost ~]# awk '{if($1>23){print "第一个字段的值大于23:"$1}else{print "第一个字段的值小于23:"$1}}' test.txt 
第一个字段的值大于23:121
第一个字段的值小于23:23
第一个字段的值小于23:23

10.9 动作中可以用赋值运算符来修改原数据

[root@localhost ~]# cat test.txt 
121	0.1	0.9	33
23	0.8	2323	34
23	0.9	sdf	sdf
[root@localhost ~]# awk '{$1="andy" ; print$0}' test.txt 
andy 0.1 0.9 33
andy 0.8 2323 34
andy 0.9 sdf sdf

[root@localhost ~]# awk '{$1-=100 ; print$0}' test.txt 
21 0.1 0.9 33
-77 0.8 2323 34
-77 0.9 sdf sdf

十一 awk的脚本编程

11.1 条件判断

11.1.1 if语句

格式:{if(表达式) {语句;语句;…}}

[root@localhost ~]# ss -an |awk '{if($2=="LISTEN"){count++;print$2}} END{print count}'
LISTEN
LISTEN
2

1.1.2 if…else语句

格式:{if(表达式) {语句;语句;…} else{语句;语句;…}}

[root@localhost ~]# ss -an |awk '{if($2=="LISTEN"){l++} else{o++}} END{print "监听端口个数:" l ; print "其他端口个数:" o}'
监听端口个数:41
其他端口个数:248

11.1.3 if…else if…else语句

格式:{if(表达式1) {语句;语句;…} else if(表达式2) {语句;语句;…} else{语句;语句;…}}

[root@localhost ~]# ss -an |awk '{if($2=="LISTEN"){l++} else if($2=="ESTAB"){e++} else{o++}} END{print "监听端口个数:" l ; print "ESTAB端口个数:" e ; print "其他端口个数:" o}'
监听端口个数:41
ESTAB端口个数:139
其他端口个数:109

11.2 循环

11.2.1 while

格式:i=1; while(i<5){语句1;语句2;i++}

[root@localhost ~]# cat test.txt 
121	0.1	0.9
23	0.8	232
[root@localhost ~]# awk '{i=1; while(i<=NF){$i+=100;print$i;i++}}' test.txt 
221
100.1
100.9
123
100.8
332

[root@localhost ~]# awk '{i=1; while(i<=NF){$i+=100;i++}; {print$0}}' test.txt 
221 100.1 100.9
123 100.8 332

11.2.2 for

格式: for(i=1;i<5;i++){语句1;语句2}

 [root@localhost ~]# cat test.txt 
121	0.1	0.9
23	0.8	232
[root@localhost ~]# awk '{for(i=1;i<3;i++){print$0}}' test.txt 
121	0.1	0.9
121	0.1	0.9
23	0.8	232
23	0.8	232

十二 awk的数组

12.1 awk的不分普通数组和关联数组

[root@localhost ~]# awk 'BEGIN{FS=":"} {lst1[++i]=$1} END{print lst1[1]}' /etc/passwd
root

[root@localhost ~]# ss -ant |awk '{lst1[$1]++} END{for (i in lst1){print i,lst1[i]}}'
LISTEN 7
ESTAB 1
State 1

12.2 awk数组的遍历-用索引便利

for (i in 数组){print i,数组[i]}
其中i是索引;数组[i]是值

12.3 使用awk数组统计数据的使用原则

将需要统计的数据(某一字段)作为数组的索引去++

十三 awk的内置函数

13.1 length函数计算字符串的长度

[root@DTOS data]# awk -F":" 'length($1)==4 {print$1;count++} END{print "count is:",count}' /etc/passwd
root
sync
halt
mail
dbus
sshd
count is: 6

13.2 sub函数是字符串替换函数

[root@DTOS data]# echo "zhang_andy_zhang" |awk 'sub(/zhang/,"wang")'
wang_andy_zhang

13.3 gsub函数是字符串全局替换函数

[root@DTOS data]# echo "zhang_andy_zhang" |awk 'gsub(/zhang/,"wang")'
wang_andy_wang

13.4 int函数是去一个字符串最前面的整数部分

[root@localhost ~]# var1=3%; var2=3.3%; var3=3test; var4=%3
[root@localhost ~]# awk "BEGIN{print int(\"$var1\")}"
3
[root@localhost ~]# awk "BEGIN{print int(\"$var2\")}"
3
[root@localhost ~]# awk "BEGIN{print int(\"$var3\")}"
3
[root@localhost ~]# awk "BEGIN{print int(\"$var4\")}"
0

十四 awk使用变量

14.1 使用外部变量

14.1.1 在双引号下使用

awk  "函数(\"$变量名\")")

在这里插入图片描述

[root@DTOS data]# var="zhang"
[root@DTOS data]# echo "wang tony" | awk "sub(/wang/,$var)"
 tony
[root@DTOS data]# echo "wang tony" | awk "sub(/wang/,"$var")"
 tony
[root@DTOS data]# echo "wang tony" | awk "sub(/wang/,'$var')"
awk: cmd. line:1: sub(/wang/,'zhang')
awk: cmd. line:1:            ^ invalid char ''' in expression
awk: cmd. line:1: sub(/wang/,'zhang')
awk: cmd. line:1:            ^ syntax error
[root@DTOS data]# echo "wang tony" | awk "sub(/wang/,\'$var\')"
awk: cmd. line:1: sub(/wang/,\'zhang\')
awk: cmd. line:1:            ^ backslash not last character on line
awk: cmd. line:1: sub(/wang/,\'zhang\')
awk: cmd. line:1:            ^ syntax error
[root@DTOS data]# echo "wang tony" | awk "sub(/wang/,\"$var\")"
zhang tony
awk  "{\"$变量名\"}"
[root@DTOS data]# var="zhang"
[root@DTOS data]# echo "wang tony" | awk "{print \"$var\"}"
zhang

14.1.2 在单引号下使用

“’”$变量名"’"
在这里插入图片描述

[root@DTOS data]# var="zhang"
[root@DTOS data]# echo "wang tony" | awk 'sub(/wang/,"'"$var"'")'
zhang tony

awk ‘{"’"$变量名"’"}’

[root@DTOS data]# var="zhang"
[root@DTOS data]# echo "wang tony" | awk '{print "'"$var"'"}'
zhang

14.2 使用awk内用v参数定义的变量

[root@andy1 grub2]# echo "zhang andy zhang" |awk -v var1="wang" '{print var1}'
wang

[root@andy1 grub2]# echo "zhang andy zhang" |awk -v var1="wang" '{sub(/zhang/,var1);print$0}'
wang andy zhang

十五 将awk输出的字符串作为一个命令让bash执行

15.1 方法一

用管道交给bash

 [root@localhost ~]# arp -n |awk '/^[0-9]/{print "arp -d "$1}' |bash

15.2 方法二

把awk的输出作为参数交给xargs后的命令处理

 [root@localhost ~]# arp -n |awk '/^[0-9]/{print $1}' |xargs -t -n1 arp -d
arp -d 192.168.1.58 
arp -d 192.168.1.217 
arp -d 192.168.1.100 
arp -d 192.168.1.251 
arp -d 192.168.1.235 
arp -d 192.168.1.241 

 或
[root@localhost ~]# arp -n |awk '/^[0-9]/{print $1}' |xargs -t -I @ arp -d @
arp -d 192.168.1.58 
arp -d 192.168.1.100 
arp -d 192.168.1.251 

十六 用rand函数取到随机值

rand()函数是随机产生一个0到1之间的保留小数点后6位的小数值,例如0.217788;
想得到一个1到7之间整数的一个随机值需要乘以100得到21.7788,然后再对7取余,结果是0.7788,int()取整是0了,我们要获得1~7的随机数,所以加1,整个表达式才是 int(rand()*100%7+1)

[root@DTOS ~]# awk '{print int(rand()*100%7+1)}'

3

2

1

2

3

6
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值