shell编程三剑客awk

本文详细介绍了awk编程语言的基础知识,包括其工作原理、语法、内部变量、格式化输出、模式与动作、变量使用、条件判断、循环和数组操作。通过实例展示了如何使用awk进行文本和数据处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.前言
awk 是一种编程语言,用于在linux/unix下对文本和数据进行处理。
数据可以来自标准输入、一个或多个文件,或其它命令的输出。
它支持用户自定义函数和动态正则表达式等先进功能,awk的处理文本和数据的方式是这样的,它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。
如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Peter Weinberger、 Kernighan。
二.工作原理
#awk -F: ‘{print $1,$3}’ /etc/passwd
(1)awk使用一行作为输入,并将这一行赋给内部变量$0,每一行也可称为一个记录,以换行符结束

(2)然后,行被:(默认为空格或制表符)分解成字段(或域),每个字段存储在已编号的变量中,从$1开始,
最多达100个字段

(3)awk输出之后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔
成字段并进行处理。该过程将持续到所有行处理完毕
在这里插入图片描述三.语法
awk [options] ‘commands’ filenames (推荐)
==options:
例如:-F 定义输入字段分隔符,默认的分隔符是空格或制表符(tab)
==command(时空):
BEGIN{} {} END{}
BEGIN{}: begin发生在行处理前(注意大写)
{}:行处理时,读一行执行一次
END{}:行处理后
示例:

示例
	#awk 'BEGIN{print 1/2} {print "ok"} END{print "-----------"}' /etc/hosts
		0.5
ok
ok
ok
-----------
	# awk 'BEGIN{print 1/2}{print "-----";print $0}END{print "HOHO"}' /etc/hosts
		0.5
-----
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
-----
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
HOHO

四.内部变量
1.FS 输入字段分隔符(默认空格)

[root@localhost ~]# awk  'BEGIN{FS=":"}  {print $1,$2}'     4.txt
root x
bin x
daemon x
adm x
lp x
sync x
shutdown x
halt x
mail x
operator x

2.OFS 输出字段分隔符

[root@localhost ~]# awk  'BEGIN{FS=":";OFS="++"}{print $1,$2,$3}'      4.txt
root++x++0
bin++x++1
daemon++x++2
adm++x++3
lp++x++4
sync++x++5
shutdown++x++6
halt++x++7
mail++x++8
operator++x++11

3.RS 输入记录(行)分隔符,默认换行符

[root@localhost ~]# awk -F:  'BEGIN{RS="r"}{print $1,$2}'     4.txt
 
oot x
oot /
oot /bin/bash1
bin
/adm /sbin/nologin4
lp
/spool/lpd /sbin/nologin5
sync
/spool/mail /sbin/nologin9
ope
ato 
 x
ato 
 /
oot /sbin/nologin10

4.OFS 输出记录(行)分隔符,默认换行符

[root@localhost ~]# awk -F:  'BEGIN{ORS="r"}{print $1,$2}'     4.txt
root xrbin xrdaemon xradm xrlp xrsync xrshutdown xrhalt xrmail xroperator xr

5.FNR 多文件独立编号
在这里插入图片描述6.NR 多文件汇总编号
在这里插入图片描述7.NF 字段总数
在这里插入图片描述五.格式化输出

print  函数
	[root@localhost ~]# date |awk '{print "Month: " $2 "\nYear: " $1}'
Month: 11月
Year: 2017年

		\n换行符
		想输出文字,用引号
	[root@localhost ~]# awk -F: '{print "username is: " $1 "\t uid is: " $3}' /etc/passwd | head -1
username is: root	 uid is: 0
	[root@localhost ~]# awk -F: '{print "\tusername and uid: " $1,$3 "!"}' /etc/passwd  | head -1
	username and uid: root 0!

在这里插入图片描述

printf 函数
	语法
		%s 字符类型
		%d 数值类型
		%f 浮点型,可以定义保留
		占15字符
		- 表示左对齐,默认是右对齐
		printf默认不会在行尾自动换行,加\n
		, 逗号,输出字段分隔符
	示例
		[root@localhost ~]# awk -F: '{printf "%-10s %-10s %-15s\n", $1,$2,$3}' /etc/passwd | head 
root       x          0              
bin        x          1              
daemon     x          2              
adm        x          3              
lp         x          4              
sync       x          5              
shutdown   x          6              
halt       x          7              
mail       x          8              
operator   x          11  
这是由于xmind的对齐导致的。
		[root@localhost ~]# awk -F: '{printf "|%-15s| %-10s| %-15s|\n", $1,$2,$3}' /etc/passwd | head
|root           | x         | 0              |
|bin            | x         | 1              |
|daemon         | x         | 2              |
|adm            | x         | 3              |
|lp             | x         | 4              |
|sync           | x         | 5              |
|shutdown       | x         | 6              |
|halt           | x         | 7              |
|mail           | x         | 8              |
|operator       | x         | 11             |

		[root@localhost ~]# awk -F: '{printf "|%-15s| %-15s| %0.1f|\n", $1,$2,$3}' /etc/passwd | head
|root           | x              | 0.0|
|bin            | x              | 1.0|
|daemon         | x              | 2.0|
|adm            | x              | 3.0|
|lp             | x              | 4.0|
|sync           | x              | 5.0|
|shutdown       | x              | 6.0|
|halt           | x              | 7.0|
|mail           | x              | 8.0|

在这里插入图片描述六.模式(正则表达)和动作
1.概念
任何awk语句都由模式和动作组成。模式部分决定动作语句何时触发及触发事件。
如果省略模式部分,动作将时刻保持执行状态。每一行都会有动作。
模式可以是任何条件语句或复合语句或正则表达式。有模式的话,就是对模式对应的行进行动作。
模式:可以是条件测试,正则,复合语句
动作:可以是打印,计算等。
2.数值比较
目的
比较表达式采用对文本进行比较,只有当条件为真,才执行指定的动作。比较表达式使用关系运算符,用于比较数字与字符串。
关系运算符 语法
< 小于 x<y
<= 小于或等于 x<=y
== 等于 x==y
!= 不等于 x!=y >= 大于等于 x>=y > 大于 x>y
示例

# awk -F: '$3 == 0' /etc/passwd 
# awk -F: '$3 == 1' /etc/passwd 
# awk -F: '$3 < 10' /etc/passwd
== 也可以用于字符串判断
# awk -F: '$7 == "/bin/bash"' /etc/passwd
# awk -F: '$1 == "alice"' /etc/passwd

算术 运算
语法 + - * / %(模) (幂2^3)
示例
awk -F: ‘$3 * 10 > 500’ /etc/passwd
多条件
&& 逻辑与 a&&b
|| 逻辑或 a||b
! 逻辑非 !a
示例:

# awk -F: '$1~/root/ && $3<=15'	 /etc/passwd
# awk -F:	 '$1~/root/ || $3<=15'		 /etc/passwd
# awk -F:	 '!($1~/root/ || $3<=15)' 	/etc/passwd

范围模式
语法:awk ‘/从哪里/,/到哪里/’ filename
awk -F: ‘/adm/,/lpd/’ /etc/passwd
从adm到ldp,显示出来,注意避免匹配重复的字段。
七.awk脚本编程
1.变量:awk调用变量
自定义内部变量 -v
awk -v user=root -F: ‘$1 == user’ /etc/passwd
外部变量 “ ‘ ”
双引号
name=cuy 变量
[root@localhost ~]# echo “sgdg hdhjhd” | awk “{print $1, “$name”}”
sgdg cuy
单引号

单引号
	# var="bash"
# echo "unix script" |awk '{print $1,"'"$var"'"}'
unix  bash
注意使用单引号时,内部需要用双引转义

条件&判断
1.if语句 单条件测试
格式 {if(表达式){语句;语句;…}}
示例:如果$3是0,就说他是管理员
在这里插入图片描述2.if…else语句 双条件
格式 {if(表达式){语句;语句;…}else{语句;语句;…}}
{if(){}else{}}
如果第三列是0,打印该行第一列,否则打印第七列,登录shell
示例:
在这里插入图片描述统计管理员和系统用户数量
在这里插入图片描述if…else if…else语句: 多条件
格式 {if(表达式1){语句;语句;…}else if(表达式2){语句;语句;…}else if(表达式3){语句;语句;…}else{语句;语句;…}}
if(){}else if (){}else if(){}else{}
题目:显示出三种用户的信息
管理员:管理员ID为0
内置用户:用户ID<1000
普通用户: 用户ID>999

在这里插入图片描述在这里插入图片描述题目:统计出三种用户的数量
管理员数量:管理员ID为0
内置用户数量:用户ID<1000
普通用户数量: 用户ID>999
在这里插入图片描述3.循环
while
循环打印10个数字
awk ‘BEGIN{ while(i<=10){print i; i++} }’
第一行打印十次
awk -F: ‘{ i=1;while(i<=9) {print $0; i++}}’ passwd
for
循环打印5个数字
awk -F: ‘{ while(i<=9) {print $0; i++}}’ passwd
将每行打印10次
awk -F: ‘{ for(i=1;i<=10;i++) {print $0} }’ /etc/passwd
打印每一行的每一列
awk -F: ‘{ for(i=1;i<=NF;i++) {print $i} }’ passwd

4.数组
定义数组
将用户名定义为数组的值,打印第一个值
awk -F: ‘{username[++i]=$1} END{print username[1]}’ /etc/passwd
打印全部值
awk -F: ‘{username[++i]=KaTeX parse error: Expected 'EOF', got '}' at position 2: 1}̲ END{for(i in u…NF]++} END{ for(i in shells){print i,shells[i]} }’ /etc/passwd

$NF 最后一列的字段内容
{}行处理
把统计的对象,作为索引。每次递增。
Print i 打印索引
Shells[i] 数组加索引,显示的就是值。
6.awk例子

	# awk '/west/' datafile
		匹配west
	# awk '/^north/' datafile
		以north开头
	# awk '$3 ~ /^north/' datafile
		第三列 匹配 north开头的
	# awk '/^(no|so)/' datafile
		no或者so 开头
	# awk '{print $3,$2}' datafile
		打印第23列,逗号引用分隔符。默认引用OFS=" "
	# awk '{print $3 $2}' datafile
		打印第23列,没有分隔符
	# awk '{print $0}' datafile
		打印记录,默认整行
	# awk 'END {print "Number of fields: "NF}' datafile 
		格式化文字“字段数”:列数
			[root@localhost ~]# awk '{print "Number of fields: "NF}'  /etc/hosts
Number of fields: 5
Number of fields: 5
[root@localhost ~]# awk '{print "Number of fields: "$ NF}'  /etc/hosts 第五列
Number of fields: localhost4.localdomain4
Number of fields: localhost6.localdomain6
	# awk '/northeast/{print $3,$2}' datafile
		匹配north行的第3,2列
	# awk '/E/' datafile
		匹配包含E的所有行
	# awk '/^[ns]/{print $1}' datafile
		以n或s开头行的第一列
	# awk '$5 ~ /\.[7-9]+/' datafile
		第五列 匹配 .1到多个7,8,9的行
	# awk '$2 !~ /E/{print $1,$2}' datafile
		第二列 中不包含E的行,打印第1,2列。
	# awk '$3 ~ /^Joel/{print $3 " is a nice boy."}' datafile
		在第三列中匹配 以Joel开头的行,打印行中的第3列
	# awk '$8 ~ /[0-9][0-9]$/{print $8}' datafile
		匹配第八列,两个数字结尾,打印第八列
	# awk '$4 ~ /Chin$/{print "The price is $" $8 "."}' datafile
		在第四列中 匹配 Chin结尾的字段, 格式化文字加第八列带个点
	# awk '/Tj/{print $0}' datafile
		匹配Tj的行
	# awk -F: '{print $1}' /etc/passwd
		冒号分割打印第一列
	# awk -F"[ :]" '{print NF}' /etc/passwd
		以冒号或空格作为字段分隔符 ,并打印列数
	# awk -F"[ :]+" '{print NF}' /etc/passwd 
		以1到多个冒号或空格作为字段分隔符 ,并打印列数
	# awk '$7 == 5' datafile
		打印第七列是5 的行
	# awk '$2 == "CT" {print $1, $2}' datafile
		打印第二列是CT的行的第1,2列
	# awk '$7 != 5' datafile
		打印第七列不等于5的行
	# awk '$7 < 5 {print $4, $7}' datafile
		打印第七列小于5的行
	# awk '$6 > .9 {print $1,$6}' datafile
		打印第6列大于.9的行的第1,6列
	# awk '$8 <= 17 {print $8}' datafile
		打印第八列小于等于17的行的第八列
	# awk '$8 >= 17 {print $8}' datafile
		打印第八列大于等于17的行的第八列
	# awk '$8 > 10 && $8 < 17' datafile
		第八列大于10,并小于17的行。
	# awk '$2 == "NW" || $1 ~ /south/ {print $1, $2}' datafile
		第二列有NW,或者,第一列包含south的行,只打印第1,2列
	# awk '!($8 == 13){print $8}' datafile
		第八列不等于13,打印匹配行的第八列($8!=13)
	# awk -F":" '/root/  {print $3 + 10}' /etc/passwd
		匹配root字段,第三列+10并打印。
	# awk '/southem/{print $8 + 10}' datafile
		匹配southerm,打印第八列+10
	# awk '/southem/{print $5 + 10.56}' datafile
		匹配southerm,打印第5列+10.56
	# awk '/southem/{print $8 - 10}' datafile
		匹配southerm,打印第八列-10
	# awk '/southem/{print $8 / 2 }' datafile
		匹配southerm,打印第八列除以2
	# awk '/southem/{print $8 / 3 }' datafile
		匹配southerm,打印第八列除以3
	# awk '/southem/{print $8 * 2 }' datafile
		匹配southerm,打印第八列乘以2
	# awk '/southem/{print $8 % 2 }' datafile
		取余数
	# awk '$3 ~ /^Suan/ {print "Percentage: "$6 + .2 " Volume: " $8}' datafile
		第三列正则匹配以Suan开头的,打印第6列加0.2 并且打印第八列
	# awk '/^western/,/^eastern/' datafile
		从以westem开头到以eastem开头的行
	# awk '{print ($7 > 4 ? "high "$7 : "low "$7)}' datafile 
		//三目运算符 a?b:c 条件?成立结果1:不成立结果2
第三列小于4显示high$7
第三列大于4显示low$7
	# awk '$3 == "Chris" {$3 = "Christian"; print $0}' datafile
		 赋值运算符,$3=christian
[root@localhost ~]# awk -F":" '$3 == 0 {$3="chaoji";print $0}' /etc/passwd
root x chaoji 0 root /root /bin/bash
	# awk '/Derek/ {$8+=12; print $8}' datafile  
		匹配Derek的行,为$8列赋值,$8=$8+12,再打印出$8
	# awk '{$7%=3; print $7}' datafile 
		//$7 %= 3等价于$7 = $7 % 3
先将第七列取余,再赋值给第七列,打印第七列
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值