awk命令的用法
AWK 是一种处理文本文件的语言,是一个强大的文本分析工具。
之所以叫 AWK 是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。
语法
awk [选项参数] 'script' var=value file(s)
或
awk [选项参数] -f scriptfile var=value file(s)
awk脚本
关于 awk 脚本,我们需要注意两个关键词 BEGIN 和 END。
BEGIN{ 这里面放的是执行前的语句 }
END {这里面放的是处理完所有的行后要执行的语句 }
{这里面放的是处理每一行时要执行的语句}
实例:
[root@wxy ~]# awk 'BEGIN{print "姓名\t\t年龄\nyaya\t\t20\nhuanhuan\t19\njackson\t\t25\nwahaha\t\t18"}'
姓名 年龄
yaya 20
huanhuan 19
jackson 25
wahaha 18
打印年龄
[root@wxy ~]# awk '{print $2}' ww
年龄
20
19
25
18
[root@wxy ~]# echo|awk 'BEGIN{print "姓名\t\t年龄\nyaya\t\t20\nhuanhuan\t19\njackson\t\t25\nwahaha\t\t18"}' |awk '{print $2}'
年龄
20
19
25
18
模式匹配
当awk读入一行时,它试图匹配脚本中的每个模式匹配规则。只有与一个特定的模式相匹配的输入行才能成为操作对象。如果没有指定操作,与模式相匹配的输入行将被打印出来(执行打印语句是一个默认操作)。
[root@wxy ~]# vim awkscript
[root@wxy ~]# cat awkscript
/[0-9]+/{print "这是一个数字"}
/[a-zA-Z]+/{print "这是一个字符串"}
/^$/{print "这是一个空行"}
[root@wxy ~]# awk -f awkscript
2
这是一个数字
w
这是一个字符串
这是一个空行
ctrl+d 退出
程序脚本的注释
在写脚本时添加注释是一个好的习惯。注释以字符“#”开始,以换行符结束。和sed不同,awk 允许在程序的任何地方添加注释。
注意:如果以命令行的方式提供 awk程序,而不是将它写入一个文件中,那么在程序的任何地方都不能用单引号,否则shell将对它进行解释而导致错误。当我们开始编写叫本事,我们将用注释来对脚本进行描述:
# blank. awk -- Print message for each blank line.广$/ { print "This is a blank line." ]
注释指出了脚本的名字是blank.awk,并简洁的描述了脚本的功能。对于较长的脚本,注释可以用来描述输入文件的预期的结构。例如,在下一节,我们将学习编写脚本来读取包含姓名和电话号码的文件。这个程序的介绍性注释如下:
# blodklist.awk-打印表格中的名字和地址。
#字段:名字、公司、街道、城市、州和邮编、电话
将这些信息嵌入在程序脚本中是很有用的,因此除非输入文件的结构和所编写的程序脚本中的结构一直,否则将无法工作。
记录和字段
awk假设它的输入是有结构的,而不只是一串无规则的字符。在最简单的情况下,它将每个输入行作为一条记录,而将由空格或制表符(tab)分隔的单词作为字段(用来分隔字段的字符被称为分隔符,默认的分隔符就是空格,并且不管有多少个空格,它都会合并成一个)。
字段和引用的分离
awk允许使用字段操作符$来指定字段。在该操作符后面跟着一个数字或变量,用于标识字段的位置。“$1”表示第一个字段,“$2”表示第二个字段等等。“$0”表示整个输入记录。
1)正则内容
[root@wxy ~]# awk -F: '/^root/{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
2)~匹配,!~不匹配
[root@wxy ~]# awk -F: '$7!~/nologin/{print}' /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
wxy:x:1000:1000:wxy:/home/wxy:/bin/bash
student01:x:1001:1001::/home/student01:/bin/bash
yy:x:1002:1002::/home/yy:/bin/bash
3)==,!=,>=,<=,>,<等,输出第二行文本
[root@wxy ~]# awk 'NR==2{print}' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
4)&&逻辑与:期望多条件都成立
[root@wxy ~]# awk -F: '$3>=0&&$3<=10{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
/取出本机ip地址
[root@wxy ~]# ip a|grep 'inet '|grep -v '127.0.0.1'|awk -F'[ /]+' '{print $3}'
192.168.235.135
下面这个正则表达式可以分段进行解释。“1?”表示出现零个或一个1;“(-I)?”表示在随后的位置上查找一个连字符或一个空格,或什么也没有;“(?”表示查找零个或一个左括号;反斜杠能够防止将“(”解释为用于分组的元字符;“[O-9]+”表示查找一个或多个数字;注意我们采用了简便的方法,仅指定一到多位数字,而不是精确地指定3位数字。在随后的位置,我们查找一个可选的右括号,接着查找一个空格或一个连字符,或什么也没有。然后用”[O~9]+”查找一到多位数字,随后跟一个连字符,最后跟一到多位数字。
[root@wxy ~]# cat test
707-724-0000
(707) 724-0000
(707)724-0000
1-707-724-0000
1 707-724-0000
1(707)724-0000
[root@wxy ~]# awk '/1?[- ]?\(?[0-9]+\)?[- ]?[0-9]+-[0-9]+/' test
707-724-0000
(707) 724-0000
(707)724-0000
1-707-724-0000
1 707-724-0000
1(707)724-0000
/匹配(707) 724-0000,(707)724-0000 两行
[root@wxy ~]# awk '/^\([0-9]+\) ?[0-9]+-[0-9]+/' test
(707) 724-0000
(707)724-0000
// "^" 开头
求平均成绩
[root@wxy ~]# cat score.awk
#!/bin/awk -f
#运行前
BEGIN {
math = 0
english = 0
computer = 0
printf "NAME NO. MATH ENGLISH COMPUTER TOTAL\n"
printf "---------------------------------------------\n"
}
#运行中
{
math+=$3
english+=$4
computer+=$5
printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5
}
#运行后
END {
printf "---------------------------------------------\n"
printf " TOTAL:%10d %8d %8d \n", math, english, computer
printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR
}
[root@wxy ~]# awk -f score.awk score.txt
NAME NO. MATH ENGLISH COMPUTER TOTAL
---------------------------------------------
Marry 2143 78 84 77 239
Jack 2321 66 78 45 189
Tom 2122 48 77 71 196
Mike 2537 87 97 95 279
Bob 2415 40 57 62 159
---------------------------------------------
TOTAL: 319 393 350
AVERAGE: 63.80 78.60 70.00
表达式
可以使用表达式来存储、操作和检索数据,这些操作与sed中的有很大的区别,但这是大多数程序设计语言所具有的共同特性。
一个表达式通过计算返回一个值。表达式由数字和字符串常量、变量、操作符、函数和正则表达式组成。
常量有两种类型:字符串型或数字型(“red”或1)。字符串在表达式中必须用引号括起来。
常用的转义序列:
\n 换行符
\t 水平制表符
变量是引用值的标识符。定义变量只需要为它定义一个名字并将数据赋给它即.可。变量名只能由字母、数字和下划线组成。而且不能以数字开头。变量名的大小写很重要: Salary 和salary是两个不同的变量,变量不必进行说明,你不必告诉awk什么类型的数据存储在一个变量中。每个变量有一个字符串型值和数字型值,awk能够根据表达式的前后关系来选择合适的值(不包含数字的字符串值为0)。变量不必初始化。awk 自动将它们初始化为空字符串,如果作为数字,它的值为0。
运算符
运算符 | 描述 |
---|---|
= += -= *= /= %= ^= **= | 赋值 |
?: C | 条件表达式 |
&& | 逻辑与 |
~ 和 !~ | 匹配正则表达式和不匹配正则表达式 |
< <= > >= != == | 关系运算符 |
空格 | 连接 |
+ - | 加,减 |
* / % | 乘,除与求余 |
+ - ! | 一元加,减和逻辑非 |
^ *** | 幂 |
++ – | 增加或减少,作为前缀或后缀 |
$ 字 | 段引用 |
in | 数组成员 |
赋值操作符
操作符 | 定义 |
---|---|
++ | 变量 加1 |
– | 变量减1 |
+= | 将加的结果赋给变量 |
-+ | 将减的结果赋给变量 |
*= | 将乘的结果赋给变量 |
/= | 将除的结果赋给变量 |
%= | 将取模的结果赋给变量 |
^= | 将取幂的结果赋给变量 |
**= | 将取幂的结果赋给变量 |
内建变量
变量 | 描述 |
---|---|
$n | 当前记录的第n个字段,字段间由FS分隔 |
$0 | 完整的输入记录 |
ARGC | 命令行参数的数目 |
ARGIND | 命令行中当前文件的位置(从0开始算) |
ARGV | 包含命令行参数的数组 |
CONVFMT | 数字转换格式(默认值为%.6g)ENVIRON环境变量关联数组 |
ERRNO | 最后一个系统错误的描述 |
FIELDWIDTHS | 字段宽度列表(用空格键分隔) |
FILENAME | 当前文件名 |
FNR | 各文件分别计数的行号 |
FS | 字段分隔符(默认是任何空格) |
IGNORECASE | 如果为真,则进行忽略大小写的匹配 |
NF | 一条记录的字段的数目 |
NR | 已经读出的记录数,就是行号,从1开始 |
OFMT | 数字的输出格式(默认值是%.6g) |
OFS | 输出字段分隔符,默认值与输入字段分隔符一致。 |
ORS | 输出记录分隔符(默认值是一个换行符) |
RLENGTH | 由match函数所匹配的字符串的长度 |
RS | 记录分隔符(默认是一个换行符) |
RSTART | 由match函数所匹配的字符串的第一个位置 |
SUBSEP | 组下标分隔符(默认值是/034) |
商品脚本
[root@wxy ~]# cat breakfast
热干面 5
杂酱面 8
重庆小面 6
三鲜粉面 7
[root@wxy ~]# cat script.sh
#!/bin/bash
echo "想吃点啥?我这儿有:"
awk '{print NR"." $1,$2"元"}' breakfast
read -p "输入想购买的早餐:" choice
read -p "输入购买的数量:" num
awk -vcount=$num -vline=$choice 'NR==line{print "您买了"count"碗"$1,"花了"$2*count"元" }' breakfast
echo 帅哥美女明早又来哦!
运行脚本:
[root@wxy ~]# source script.sh
想吃点啥?我这儿有:
1.热干面 5元
2.杂酱面 8元
3.重庆小面 6元
4.三鲜粉面 7元
输入想购买的早餐:2
输入购买的数量:4
您买了4碗杂酱面 花了32元
帅哥美女明早又来哦!
关系操作符和布尔操作符
关系操作符和布尔操作符用于在两个表达式之间进行比较。
操作符 | 描述 |
---|---|
< | 小于 |
> | 大于 |
<= | 小于或等于 |
>= | 大于或等于 |
== | 相等 |
!= | 不相等的 |
~ | 匹配 |
!~ | 不匹配 |