一.前言
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
先将第七列取余,再赋值给第七列,打印第七列