[awk笔记1] 快速入门

Source

The awk programming language, Chapter1 Note

中文版参考 https://github.com/wuzhouhui/awk

目录

AWK程序的结构

运行AWK程序

输出

简单的输出print

格式化输出printf

选择

通过文本内容选择

模式的组合

数据验证

BEGIN、END

用AWK计算

计数

计算总和与平均数

取最大值

字符串拼接

打印最后一行

内建函数length

流程控制语句

If-Else 语句

While 语句

For 语句

数组


AWK程序的结构

emp.data 包含有名字、每小时工资(以美元为单位)、工作时长、每一行代表一个雇员的记录

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

现在你想打印每位雇员的名字以及他们的报酬(每小时工资乘以工作时长), 而

(1)打印工作时长大于零的雇员及其报酬

awk '$3 > 0 { print $1, $2 * $3 }' emp.data

Output:
Kathy 40
Mark 100
Mary 121
Susie 76.5

说明:
运行的程序用单引号包围起来,从输入文件emp.data 获取数据
运行的程序由一个单独的模式-动作语句(pattern-action statement) 组成
模式 "$3 > 0" 扫描每一个输入行,如果该行的第三列大于零, 则动作


awk 的基本操作 陆续地扫描每一行, 搜索可以被模式匹配的行;每匹配一个模式 => 动作执行 
awk 程序是由一个或多个模式-动作语句组成的序列;在一个模式–动作语句中, 模式或动作可以省略其一, 但不能两者同时被省略

运行AWK程序

运行一个awk 程序有多种方式

(1)awk 'program' <input files...>

(2)也可以在命令行上省略输入文件, 只要键入
awk 'program'
在这种情况下, awk 会将program 应用到你接下来在终端输入的内容上面, 直到键入一个文件结束标志(Unix系统是组合键Control-d)

# awk '$3 > 0 { print $1, $2 * $3 }'
Beth    4.00    0
Dan     3.75    0
Kathy   4.00    10
Kathy 40  --> 终端输出
Mark    5.00    20
Mark 100  --> 终端输出
...

(3)如果程序比较长, 可以将其放在一个文件中

programfile内容为 
$3 > 0 { print $1, $2 * $3 }

执行
# awk -f programfile emp.data

输出
Kathy 40
Mark 100
Mary 121
Susie 76.5

说明:选项-f --> awk 从文件中提取程序

输出

简单的输出print

(1)打印每一行: { print } 或 { print $0 }

# awk '{ print }' emp.data 或者
# awk '{ print $0 }' emp.data

输出
Beth    4.00    0
Dan     3.75    0
Kathy   4.00    10
Mark    5.00    20
Mary    5.50    22
Susie   4.25    18

说明: $0 表示一整行

(2)打印某些字段
{ print $1, $3 }
==> 打印第一个和第三个字段

说明:在print 语句中由逗号分隔的表达式, 在输出时默认用一个空格符分隔; 由print 打印的每一行都由一个换行符终止

(3)NF, 字段的数量

(4)NR, 行号

(5)将文本放入输出中

# awk '{ print NR, "total pay for", $1, "is", $2 * $NF }' emp.data

输出
1 total pay for Beth is 0
2 total pay for Dan is 0
3 total pay for Kathy is 40
4 total pay for Mark is 100
5 total pay for Mary is 121
6 total pay for Susie is 76.5

格式化输出printf

# awk '{ printf("total pay for %s is $%.2f\n", $1, $2 * $3) }' emp.data

输出
total pay for Beth is $0.00
total pay for Dan is $0.00
total pay for Kathy is $40.00
total pay for Mark is $100.00
total pay for Mary is $121.00
total pay for Susie is $76.50

说明:使用printf 不会自动产生空格符或换行符

# awk '{ printf("%-8s $%6.2f\n", $1, $2 * $3) }' emp.data

输出
Beth     $  0.00
Dan      $  0.00
Kathy    $ 40.00
Mark     $100.00
Mary     $121.00
Susie    $ 76.50

说明:
%-8s, 将名字左对齐输出, 占用8个字符的宽度
%6.2f, 将报酬以带有两位小数的数值格式打印出来, 占用6个字符的宽度

排序输出

# awk '{ printf("%6.2f | %s\n", $2 * $3, $0) }' emp.data

输出
  0.00 | Beth   4.00    0
  0.00 | Dan    3.75    0
 40.00 | Kathy  4.00    10
100.00 | Mark   5.00    20
121.00 | Mary   5.50    22
 76.50 | Susie  4.25    18

选择

通过文本内容选择

# awk '$1 == "Susie"' emp.data 或者使用正则表达式
# awk '/Susie/' emp.data

输出
Susie   4.25    18

模式的组合

逻辑运算符包括 &&, ||, 和 !

# awk '$2 >= 4 && $2 * $3 >= 50' emp.data
Mark    5.00    20
Mary    5.50    22
Susie   4.25    18

# awk '$2 >= 4 ||  $2 * $3 >= 50' emp.data  说明:两个条件都满足的行只输出一次
Beth    4.00    0
Kathy   4.00    10
Mark    5.00    20
Mary    5.50    22
Susie   4.25    18

# awk '$2 >= 4  {print} $2 * $3 >= 50 {print} ' emp.data  说明:两个条件都满足输出两次
Beth    4.00    0
Kathy   4.00    10
Mark    5.00    20
Mark    5.00    20
Mary    5.50    22
Mary    5.50    22
Susie   4.25    18
Susie   4.25    18

数据验证

数据验证在本质上是否定: 打印可疑行

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" }

BEGIN、END

BEGIN 在第一个输入文件的第一行之前匹配
END 在最后一个输入文件的最后一行被处理之后匹配

例如,输出数据前打印表头

# awk 'BEGIN { print "NAME    RATE    HOURS"; print "" } {print}' emp.data
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

说明:可以在同一行放置多个语句, 语句之间用分号分开

用AWK计算

计数

# cat countWorkUp15
$3 > 15 { emp = emp + 1 }
END { print emp, "employees worked more than 15 hours" }

# awk -f countWorkUp15 emp.data
3 employees worked more than 15 hours

说明:当awk 的变量作为数值使用时, 默认初始值为0, 所以无需初始化emp

计算总和与平均数

# cat averPay
{ pay = pay + $2 * $3 }
END { print NR, "employees"
print "total pay is", pay
print "average pay is", pay / NR
}

# awk -f averPay emp.data
6 employees
total pay is 337.5
average pay is 56.25

取最大值

# cat maxHourRate
$2 > maxrate { maxrate = $2; maxemp = $1 }
END { print "highest hourly rate:", maxrate, "for", maxemp }

# awk -f maxHourRate emp.data
highest hourly rate: 5.50 for Mary

说明:如果有多个雇员都拥有相同的最高每小时工资, 这个程序只会打印第一个人的名字

字符串拼接

# awk '{ names = names $1 " " } END { print names }' emp.data

输出
Beth Dan Kathy Mark Mary Susie

打印最后一行

# awk 'END { print last }' emp.data   说明: 输出是空行

# awk '{ last = $0 } END { print last }' emp.data
Susie   4.25    18

说明:在END 动作里, NR的值保留了下来, $0的值没有保留

内建函数length

# cat -A emp.data
Beth^I4.00^I0$
Dan^I3.75^I0$
Kathy^I4.00^I10$
Mark^I5.00^I20$
Mary^I5.50^I22$
Susie^I4.25^I18$

# awk '{ print $0,"--", length($0) }' emp.data
Beth    4.00    0 -- 11
Dan     3.75    0 -- 10
Kathy   4.00    10 -- 13
Mark    5.00    20 -- 12
Mary    5.50    22 -- 12
Susie   4.25    18 -- 13

说明:$0 不包含换行符

流程控制语句

If-Else 语句

# cat test1
$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"
}


# awk -f test1 emp.data

输出
no employees are paid more than $6/hour

While 语句

价值计算的公式 

value = amount(1+rate)^{years}

value.txt内容如下

# interest1 - compute compound interest
# input: amount rate years
# output: compounded value at the end of each year
{ i = 1
while (i <= $3) {
printf("\t%.2f\n", $1 * (1 + $2) ^ i)
i = i + 1
}
}

键入三个数, 看一下不同的本金, 利率和时间会产生怎样的结果
例如, $1000 在6% 与12% 的利率下, 在5 年的时间的升值如下

# awk -f value.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

For 语句

可以实现与上例相同的功能

value2.txt内容如下
# interest2 - compute compound interest
# input: amount rate years
# output: compounded value at the end of each year
{ for (i = 1; i <= $3; i = i + 1)
printf("\t%.2f\n", $1 * (1 + $2) ^ i)
}


# echo "1000 0.06 5" > test
# awk -f value2.txt test
        1060.00
        1123.60
        1191.02
        1262.48
        1338.23

数组

如下实现了从最后一行倒着打印输入文件

reversePrint内容如下
# reverse - print input in reverse order by line
{ line[NR] = $0 } # remember each input line
END { i = NR # print lines in reverse order
while (i > 0) {
print line[i]
i = i - 1
}
}

# awk -f reversePrint emp.data
Susie   4.25    18
Mary    5.50    22
Mark    5.00    20
Kathy   4.00    10
Dan     3.75    0
Beth    4.00    0