20个 DEMO 了解如何使用 AWK

一.程序结构

语法结构awk [options] 'Pattern {Action}' file1 file2
示例代码 awk '$3 == 0 { print $1 }' test.txt
上述命令中,引号之间的部分是 awk 编程语言的程序.每个 awk 程序都是一个或多个模式-动作语句的程序: pattern { action }

awk 的基本操作都是一行一行地扫描输入, 搜索匹配任意程序中 parrent 的行. 对示例代码来说匹配 ‘$3 == 0’ 为真的行;

每个 pattern 依次测试每个输入行,对于匹配到 pattern 的行,其对应的动作(也许包含多步) 得到执行,然后读取下一行并继续匹配.知道所欲的输入读取完毕.

Pattern:也就是条件,一个关系表达式, awk 会朱行处理文本,处理完当前行,然后再处理下一行,如果不指定任何[条件], awk 会一行一行的处理完文件的每一行, 如果指定了[条件], 只处理满足条件的行.

awk 程序一次从输入文件中,读取一行内容并把它分割成一个一个字段,通常默认情况下, 一个字段是不包含任何空格或者制表符的连续字符序列. 当前输入的行中的第一个字段被称为 $1, 第二个是 $2, 以此类推,整个行的内容被定义为 $0, 每一行的字段数量可以不同

二.示例代码解说

test.txt 内容:

Beth 4.00 0
Dan 3.75 0
kathy 4.00 10
Mark 5.00 20
Mary 5.50 22
Susie 4.25 18

demo1

awk '$3 == 0 { print $1 }' file1 file2
打印文件 file1 和文件 file2 中第三个字段为 0 的每一行的第一个字段

demo2 (文件存放 awk 程序)

awk -f profile file1
其中 -f 选指示 awk 从指定文件中获取程序,可以使用任意文件名替换为 profile;
profile 如: {print $1}

demo3

awk '{print}' test.txtawk '{print $0}' test.txt
打印出每一行

demo4

awk '{print $1,$2}' test.txt
打印特定字段
在 print 语句中被逗号分隔的表达式,在默认情况下他们将会用一个空格分隔来输出, 每一行 print 生成的内容都会以一个换行符作为结束(这些都是默认行为,后期可以自定义)

demo5 (内建变量 NF)

awk '{print NF, $1, $NF}' test.txt
结果:

3 Beth 0
3 Dan 0
3 kathy 10
3 Mark 20
3 Mary 22
3 Susie 18

会一次打印出每一行的字段数量, 第一个字段的值 ,最后一个字段的值
在该语句中 :
NF: 字段的数量;$1:第一个字段的值 ;$NF: 最后一个字段的值

awk 会将当前输入的行有多少个字段进行统计,并且将当前行的字段数量存储在一个内建的称作为 NF 的变量中,

demo6

awk '{print $1, $2 * $3}' test.txt
可以对字段的值进行 计算后在打印出来

demo7 (内建变量 NR)

awk '{print NR, $0}' test.txt
结果:

1 Beth	4.00  	0
2 Dan	3.75	0
3 kathy	4.00	10
4 Mark	5.00	20
5 Mary	5.50	22
6 Susie	4.25	18

awk 提供另一个内建变量,叫做 NR, 它会存储当前已经读取了多少行的计数,我们可以输出 NR 为每一行加上行号

demo8

awk '{print "total pay for", $1 , "is" , $2 * $3}' test.txt
在输出的字段中间添加打印输出

demo9 (高级输出)

printf(format, value1, value2, ..., valuen)
其中 format 是包含占位符的字符串,而后面的 value 就是占位符要显示的内容(和 java 中的 String.format 类似)
案例一:awk '{ printf("total pay for %s is %.2f\n", $1, $2 * $3)}' test.txt

注意: %.2f 的意思是输入 第二个参数(也就是 $2 * $3) ,并保留两位小数;

printf 不会自动产生空格或者新的行,必须是自己来创建,所以不要忘了 \n;

案例二:awk '{ printf("%-8s %6.2f\n", $1, $2 * $3)}' test.txt

第一个 %-8s 表示将第一个参数已字符串形式在8个字符宽度的字段中左对齐输出, 第二个 %6,2 将第二个参数以数字的格式,保留小数点后两位,在6个字符宽度的字段中输出;

demo10 (排序输出)

最简单的方式,将薪酬放在第一列,然后使用 sort 命令
awk '{ printf("%6.2f %s\n", $2 * $3 , $1)}' test.txt | sort
结果:

  0.00  Beth
  0.00  Dan
 40.00  kathy
 76.50  Susie
100.00  Mark
121.00  Mary

demo11(选择)

通过对比选择
awk '$2 * $3 > 50 { printf("%6.2f %s\n", $2 * $3 , $1)}' test.txt
打印出总新薪资超过50美元的员工薪资

通过文本选择
awk '$1 == "Susie" {print $0}' test.txt
打印出第一列为 Susie 的信息

当然也可以使用正则表达式
awk '/Susie/ {print $0}' test.txt
打印任意一行包含 Susie 的信息

组合模式
awk '$2 >= 4 || $3 >= 20 {print $0}' test.txt
打印第二行大于等于4 或 第三行大于等于20 的信息

demo12 (数据验证)

实际的数据中总是会存在错误的,在数据验证-检查数据的值是否合理以及格式是否正确方面, awk 是一个优秀的工具, 数据验证本质上是否定的:不是打印具备期望属性的行,而是打印可疑的行.

NF != 3     { print $0, "number of fields is not equal to 3" }
$2 < 3.35   { print $0, "rate is below minimum wage" }
$2 > 10     { print $0, "rate exceeds $10 per hour" }
$3 < 0      { print $0, "negative hours worked" }
$3 > 60     { print $0, "too many hours worked" }

如上面程序使用的对比模式,如果没有出错,则没有输出;

demo13(BIGIN 与 END)

awk 'BEGIN {print "name rate hours"; print ""} {print $0} END {print "end "} ' test.txt
结果:

name rate hours

Beth	4.00  	0
Dan	3.75	0
kathy	4.00	10
Mark	5.00	20
Mary	5.50	22
Susie	4.25	18
end

特殊模式 BEGIN 用于匹配第一个输入文件的第一行之前的位置, END 则用于匹配处理过的最后一个文件的最后一行之后的位置;程序的动作部分你可以在一行上放多个语句, 不过要使用分号进行分割.

注意: 普通的 print “” 是打印当前输入行, 与之不同的是 print '" 会打印一个空行

demo14 (使用 awk 进行计算)

计算有 多少人工作小时数超过 15 个小时

awk '$3 > 15 {emp = emp + 1} ; $3 > 0 {print $0}; END {print emp , "employees worked more than 15 houres"}' test.txt

不仅可以使用想 NF 装的内置变量,还可以参加自己的变量用于计算,存储数据, 在 awk 中用户创建的变量不需要声明;

计算平均薪资

awk ' pay = pay + $2 * $3;
         END {printf("total employees %s, average pay is %.2f end", NR, pay/NR)};'  test.txt

结果:

kathy	4.00	10
Mark	5.00	20
Mary	5.50	22
Susie	4.25	18
total employees 6, average pay is 56.25 end

demo15(处理文本)

awk 的优势之一是能够像大多数诞处理数字一样方便的处理字符串, awk 变量可以保存数字也可以保存字符串.

这个程序会找出时薪最高的员工;

awk '$2 > maxrate {maxrate = $2; maxname = $1};
        END {print "maxrate=" ,maxrate ,". maxname=", maxname};' test.txt

结果

maxrate= 5.50 . maxname= Mary

demo16(字符串链接)

可以合并老字符串来创建新的字符串,

awk '{names = names $1 " "} ; END {print"names=" , names};' test.txt

结果:

names= Beth Dan kathy Mark Mary Susie

demo17(打印最后一行)

awk '{lastLine = $0} ; END {print lastLine }; ' test.txt
结果:

Susie	4.25	18

demo18(内置函数)

length(计算字符长度)
awk '{print $1 ,length($1)}' test.txt
结果:

Beth 4
Dan 3
kathy 5
Mark 4
Mary 4
Susie 5

案例: 行、单词以及字符的计数

awk '{nc = nc + length($0) + 1; nw = nw + NF} ; END {print "nc=" , nc , ", nw =", nw , ", nr="  , NR}' test.txt 

结果:

nc= 79 , nw = 18 , nr= 6

注意: nc 最后加上一是因为 length 不会算上每行最后的换行符;如果要计算上换行符的话.必须+1

demo19(控制语句)

if-else 语句
计算时薪超过6美元的员工的总薪酬与平均薪酬,用 if 来防范计算平均薪酬时零除的问题;

awk ' $2 > 6 {n = n + 1; pay = pay + $2 * $3};
            END {
                    if  (n > 0) 
                        print n , "employees , total pay is ", pay ,
                        "average pay is ", pay /n
                    else 
                            print "no employees are paid more than $6/hour"
            }' test.txt

结果:

no employees are paid more than $6/hour

while 语句
创建存放命令的文件:

# 计算复利
# 输入 : 钱数 利率 年数
# 输出 : 复利值
{
 i = 1;
 while (i <= $3) {
    printf("\t%.2f\n", $1 * (1 + $2) ^ i);
    i = i + 1;
 }
}

执行命令以及结果:

$ awk -f profile.txt
1000 0.06 5
	1060.00
	1123.60
	1191.02
	1262.48
	1338.23
1000 0.12 5
	1120.00
	1254.40
	1404.93
	1573.52
	1762.34

# 为注释符号,从 # 开始到行尾的文本就是注释, 会被 awk 忽略;
^ 是指数操作符;

当我们执行 awk -f profile.txt 的时候, awk 会继续让我们输入参数,也就是上面的 1000, 0.06 ,5; 在 profile 中使用 $1 $2 $3 的变量来获取相应位置的参数;

awk 会将你输入的参数看成一行, 也就是文本中的一行,然后来执行 awk 语句;和我们上面将文本放入到 test.txt 的情况一致,只是这个文本是在外面自定义的;

for 语句
for , 将大多数循环都包含的初始化,测试,以及自增压缩成一行.如下是之前利息计算的 for 版本;

for (i = i; i <= $3; i = i + 1) {
    printf("\t%.2f\n",  $1 * (i + $2) ^ i);
}

demo20 (数组)

awk 为存储一组相关的值提供了数组.虽然数组给予了 awk 很强的能力,
如下程序将按行逆序打印输入.

{ line[NR] = $0 } #记下每个输入行
END {                   # 逆序打印
    i = NR;
    while (i > 0) {
      print line[i]
      i = i - 1;
    };
}

这里注意的是 awk 中的数组并没有在 line[0] 中存值;

三.扩展

3.1 内置变量

变量名描述代码示例
FS输入字段分隔符,默认是空格awk -v FS='a' '{print $1,$2}' test.txt
OFS输出字段分隔符,默认是空格awk -v OFS='->' '{print $1,$2}' test.txt
RS输入记录分隔符.默认是换行符awk -v RS='a' '{print $1,$2}' test.txt
NFnumber of fields,当前记录中域的个数,也就是每行有多少列awk '{print NF,$1,$2}' test.txt
NRnumber of rows,已经读出的记录数,也就是行号。从1开始,有多个文件时,这个值会累加awk '{print NR,$1,$2}' test.txt
FNR各个文件分别计数的行号
FILENAME当前文件名awk '{print FILENAME,$1,$2}' test.txt'
AGRC命令行参数的个数
ARGV数组,保存命令行所传的各个参数
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值