Linux Shell——awk编程

awk模式匹配

任何awk都是由模式和动作组成,模式决定动作何时触发和触发时间,动作执行对输入行的处理。

例子:

第一种调用方式:命令

[root@localhost demo]# awk '/^$/{print "This is a blank line."}' dialer-service.conf 
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.

^$ 部分是模式,花括号部分是动作,该awk命令表示一旦输入文件行是空行,就打印"This is a blank line."。

第二种调用方式:脚本文件

[root@localhost demo]# cat scr.awk 
/^$/{print "This is a blank line."}
[root@localhost demo]# awk -f scr.awk dialer-service.conf 
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.

第三种调用方式:直接执行,不需要命令行调用

[root@localhost demo]# cat scr.awk 
#!/bin/awk -f
/^$/{print "This is a blank line."}
[root@localhost demo]# ./scr.awk dialer-service.conf 
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.

记录和域

awk将每个输入文件行定义为记录,行中的每个字符串定义为域,域之间用空格,Tab或者其他符号分隔。

// 按指定次序打印域
[root@localhost demo]# awk '{print $2,$1,$4,$3}' sturecord 
Hao Li njue 025-83481010
Zhang Ju nju 025-83466534
Wang Bin seu 025-83494883
Zhu Lin njupt 025-83680010
//打印全部域
[root@localhost demo]# awk '{print $0}' sturecord 
Li Hao 025-83481010 njue
Ju Zhang 025-83466534 nju
Bin Wang 025-83494883 seu
Lin Zhu 025-83680010 njupt		 

在$后还可以跟变量指定域号:

[root@localhost demo]# awk 'BEGIN {one=1;two=2} {print $(one+two)}' sturecord 
025-83481010
025-83466534
025-83494883
025-83680010

改变分隔符

// 默认分隔符为空格,使用-F 改为Tab键
[root@localhost demo]# awk -F"\t" '{print $3}' sturecord 
njue
nju
seu
njupt

FS变量改变分隔符:

 awk 'BEGIN {FS=","} {print $1,$3}' sturecord

关系和布尔运算符

#第一域匹配root
[root@localhost demo]# awk 'BEGIN {FS=":"} $1~/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash

#全部域匹配root
[root@localhost demo]# awk 'BEGIN {FS=":"} $0~/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

#全局不匹配nologin
[root@localhost ~]# awk 'BEGIN {FS=":"} $0!~/nologin/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mysql:x:1000:1000::/home/mysql:/bin/bash
rabbitmq:x:996:995:RabbitMQ messaging server:/var/lib/rabbitmq:/bin/bash
www:x:1002:1002::/home/www:/bin/bash
nginx:x:1003:1003::/home/nginx:/bin/bash
mosquitto:x:1004:1004::/home/mosquitto:/bin/bash
shepf:x:0:1005::/home/shepf:/bin/bash

if 语句匹配

[root@localhost ~]# awk 'BEGIN {FS=":"} {if($3<$4) print $0}' /etc/passwd
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
shepf:x:0:1005::/home/shepf:/bin/bash

#多条件精确匹配
[root@localhost ~]# awk 'BEGIN {FS=":"} {if($3==8||$4==12) print $0}' /etc/passwd
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

#多添件模糊匹配
[root@localhost ~]# awk 'BEGIN {FS=":"} {if($3~8||$4~12) print $0}' /etc/passwd
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
libstoragemgmt:x:998:997:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin

表达式

一个awk表达式可由数值、字符常量、变量、操作符、函数和正则表达式自由组合而成。变量名只能包含字母、数字和下划线,而且不能以数字开头。

案例

统计文件中的空白行

[root@localhost demo]# awk '/^$/{print x+=1}' dialer-service.conf 

计算平均成绩

[root@localhost demo]# cat sturecord 
Li Hao,025-83481010,njue,85,92,78,94,88
Ju Zhang,025-83466534,nju,89,90,75,90,86
Bin Wang,025-83494883,seu,84,88,80,92,84
Lin Zhu,025-83680010,njupt,98,78,81,87,76
[root@localhost demo]# ./src1.awk sturecord 
Li Hao 87.4
Ju Zhang 86
Bin Wang 85.6
Lin Zhu 84
[root@localhost demo]# cat src1.awk 
#!/bin/awk -f

BEGIN {FS=","}
{total=$4+$5+$6+$7+$8
avg=total/5
print $1,avg}

系统变量

awk定了许多内建变量用于设置环境信息,成为系统变量

[root@localhost demo]# awk 'BEGIN {FS=","} {print NF,NR,$0} END {print FILENAME}' sturecord 
8 1 Li Hao,025-83481010,njue,85,92,78,94,88
8 2 Ju Zhang,025-83466534,nju,89,90,75,90,86
8 3 Bin Wang,025-83494883,seu,84,88,80,92,84
8 4 Lin Zhu,025-83680010,njupt,98,78,81,87,76
sturecord

格式化输出

print语句只提供最基本的输出格式,awk借鉴了C语言的语法,定义了printf输出语句,printf的基本语法:

printf (格式控制符,参数)

格式符意义
-左对齐
width域的步长
.prec小数点右边的位数
%cASCII字符
%d整型数
%e浮点数,科学计数法
%f浮点数
%o八进制数
%s字符串
%x十六进制数

printf基本用法

# 参数是变量列表
awk 'BEGIN {FS=","} {printf("%s\t%d\n",$2,$8)}' sturecord 
025-83481010	88
025-83466534	86
025-83494883	84
025-83680010	76

# 转换为ASCII字符
awk 'BEGIN {printf("%c\n",65)}'
A
# 转换为浮点数
awk 'BEGIN {printf("%f\n",2010)}'
2010.000000
# 输出第一域和第三域,第一域控制长度15并且左对齐,不够的话用空格填充
awk 'BEGIN {FS=","} {printf("%-15s\t%s\n",$1,$3)}' sturecord 
Li Hao         	njue
Ju Zhang       	nju
Bin Wang       	seu
Lin Zhu        	njupt
# printf修饰符.prec的用法
# 保留三位小数
awk 'BEGIN {printf("%10.3f\n",2009.1012)}'
  2009.101

内置字符串函数

函数名意义
gsub(r,s)再输入文件中用s替换r
gsub(r,s,t)在t中用s替换r
index(s,t)返回s中字符串第一个t的位置
length(s)返回s的长度
match(s,t)测试s是否包含匹配t的字符串
split(r,s,t)在t上将r分成序列s
sub(r,s,t)将t中第1次出现的r替换为s
substr(r,s)返回字符串r中从s开始的后缀部分
substr(r,s,t)返回字符串r中从s开始长度为t的后缀部分
#gsub函数用法

#替换第一域上的root字符串
awk 'BEGIN {FS=":";OFS=":"} gsub(/root/,"gridsphere",$1) {print $0}' /etc/passwd
gridsphere:x:0:0:root:/root:/bin/bash

#替换全部域上的root字符串
awk 'BEGIN {FS=":";OFS=":"} gsub(/root/,"gridsphere") {print $0}' /etc/passwd
gridsphere:x:0:0:gridsphere:/gridsphere:/bin/bash
operator:x:11:0:operator:/gridsphere:/sbin/nologin
# index和length函数用法
awk 'BEGIN {print index("gridsphere","ph")}'
6
awk 'BEGIN {print length("gridsphere")}'
10
# match函数用法
# 区分大小写匹配
awk 'BEGIN {print match("gridsphere",/D/)}'
0
# 忽略大小写
awk 'BEGIN {IGNORECASE=1;print match("gridsphere",/D/)}'
4

# sub函数的用法
awk 'BEGIN {str="multiprocessor programming";sub("pro","PRO",str);printf("%s\n",str)}'
multiPROcessor programming

awk 'BEGIN {FS=","} {$1~Li sub(10,"99",$0);print $0}' sturecord 
Li Hao,025-83489910,njue,85,92,78,94,88
Ju Zhang,025-83466534,nju,89,90,75,90,86
Bin Wang,025-83494883,seu,84,88,80,92,84
Lin Zhu,025-83680099,njupt,98,78,81,87,76

# substr 函数的用法

# 返回str从第6个字符开始的后缀部分
awk 'BEGIN {str="multiprocessor programming";print substr(str,6)}'
processor programming
# 返回str从第6个字符开始的后缀部分
awk 'BEGIN {str="multiprocessor programming";print substr(str,6,9)}'
processor programming

向awk脚本传递参数

awk脚本内的变量可以在命令行中进行赋值,实现向awk脚本传递参数,变量赋值放在脚本之后,输入文件之前

awk 脚本 parameter=value 输入文件

条件语句和循环语句

if语句语法

if (条件表达式)
动作1
[else
动作2]

循环语句有三种 while、do while和for

while (条件表达式)
动作

do
动作
while (条件表达式)

for (设置计数器初值;测试计数器;计数器变化)
动作

数组

基本格式

array[index]=value

关联数组
关联数组是指数组的索引可以是字符串,也可以是数字。关联数组在索引和数组元素值之间建立起关联,对每一个数组元素,awk自动维护了一对值:索引和数组元素值。关联数组的值无需以连续的地址进行存储。

awk特别定义了一种for循环用来访问关联数组:

for (variable in array)
do something with array[variable]

# 判断数组元素是否存在
awk '
> BEGIN {data[10.15]="1200";
> if ("10.15" in data)
> print "Found element!"}'
Found element!

split函数

# 将字符串按指定分隔符分割成数组
awk 'BEGIN {print split("abc/def/xyz",str,"/")}'
3

# 将sturecord文件的第一域划分为两个元素
awk 'BEGIN {FS=","} {print split($1,name," ")}' sturecord 
2
2
2
2
# split函数所生成的数组内容
#!/bin/awk -f
BEGIN {FS=","}
{split($1,name," ");
for(i in name) print name[i]}

数组形式的系统变量

awk系统变量中有两个变量是以数组形式提供的:ARGV和ENVIRON,ARGC是ARGV数组中元素的个数。

 ./findphone.awk Zhu sturecord 
Lin Zhu njupt
[root@localhost demo]# ./findphone.awk  sturecord 
Pls. Enter a name
Li
Li Hao njue
Lin Zhu njupt

#!/bin/awk -f
BEGIN{FS=","
        # 判断是否已经输入姓名
        if(ARGC>2){
                name=ARGV[1];
                delete ARGV[1]}
        else{
                #如果没有输入姓名,提示输入
                while(!name){print "Pls. Enter a name"
                                getline name< "-"}
        }
}
$1~name {print $1,$3}

ENVIRON存储了系统的环境变量:

awk '
BEGIN {for (i in ENVIRON)
> print i "=" ENVIRON[i]}'
AWKPATH=.:/usr/share/awk
OLDPWD=/root
MAVEN_HOME=/usr/local/maven/apache-maven-3.6.3
LANG=zh_CN.UTF-8
HISTSIZE=1000
XDG_RUNTIME_DIR=/run/user/0

我们可以通过环境变量名获取值

awk 'BEGIN {print ENVIRON["AWKPATH"]}'
.:/usr/share/awk

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值