AWK 中级学习手册

一、内置函数详解

1. 数值函数

1
2
3
4
5
6
7
8
9
10
# 常用数值函数
awk 'BEGIN {
print sqrt(16) # 平方根:4
print int(3.7) # 取整:3
print rand() # 随机数:0-1之间
print srand() # 设置随机种子
print log(10) # 自然对数
print exp(2) # e的2次方
}'

2. 字符串函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 字符串处理函数
awk 'BEGIN {
str = "Hello World"

# 长度
print length(str) # 11

# 子串
print substr(str, 1, 5) # Hello
print substr(str, 7) # World

# 查找
print index(str, "World") # 7 (位置)
print match(str, /W[a-z]+/) # 7 (正则匹配位置)

# 替换
print sub(/World/, "AWK", str) # 替换第一个匹配项
print gsub(/l/, "L", str) # 替换所有匹配项

# 分割
split("a,b,c", arr, ",")
for(i in arr) print arr[i] # a b c
}'

3. 时间函数

1
2
3
4
5
6
7
# 时间相关函数
awk 'BEGIN {
print systime() # 当前时间戳
print strftime("%Y-%m-%d") # 格式化当前时间
print strftime("%H:%M:%S", systime()) # 指定时间戳格式化
}'

4. 其他实用函数

1
2
3
4
5
6
# 系统函数
awk 'BEGIN {
print system("echo Hello") # 执行系统命令
print getline # 从输入读取下一行
}'

二、自定义函数

1. 基本语法

1
2
3
4
5
function 函数名(参数列表) {
函数体
return 返回值
}

2. 实际示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 计算平均值函数
awk '
function avg(arr, n) {
sum = 0
for(i = 1; i <= n; i++) {
sum += arr&#91;i]
}
return sum / n
}

{
scores&#91;NR] = $2
}
END {
print "平均分:", avg(scores, NR)
}' students.txt

1
2
3
4
5
6
7
8
9
10
# 字符串处理函数
awk '
function format_name(first, last) {
return toupper(substr(first,1,1)) substr(first,2) " " toupper(last)
}

{
print format_name($1, $2)
}' names.txt

三、正则表达式进阶

1. 正则表达式操作符

1
2
3
4
5
6
7
8
# 基本正则
awk '/^&#91;0-9]+$/ {print "纯数字:", $0}' file.txt # 行首到行尾都是数字
awk '/\.&#91;a-zA-Z]{3,4}$/ {print "文件:", $0}' file.txt # 匹配文件扩展名

# 正则替换
awk '{gsub(/&#91;0-9]+/, "NUM"); print}' file.txt # 替换所有数字为NUM
awk '{sub(/^.*@/, ""); print}' emails.txt # 去掉邮箱前缀

2. match函数的高级用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 提取匹配内容
awk '{
if(match($0, /&#91;0-9]{4}-&#91;0-9]{2}-&#91;0-9]{2}/)) {
date = substr($0, RSTART, RLENGTH)
print "找到日期:", date
}
}' logs.txt

# 使用捕获组(GNU awk)
awk '{
if(match($0, /(&#91;0-9]{4})-(&#91;0-9]{2})-(&#91;0-9]{2})/, arr)) {
print "年:", arr&#91;1], "月:", arr&#91;2], "日:", arr&#91;3]
}
}' logs.txt

四、多维数组处理

1. 模拟多维数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 使用分隔符模拟二维数组
awk '{
matrix&#91;NR,1] = $1
matrix&#91;NR,2] = $2
matrix&#91;NR,3] = $3
}
END {
for(row = 1; row <= NR; row++) {
for(col = 1; col <= 3; col++) {
printf "%s\t", matrix&#91;row,col]
}
print ""
}
}' data.txt

2. 关联数组的复杂应用

1
2
3
4
5
6
7
8
9
10
11
12
13
# 统计每个用户在不同日期的操作次数
awk '{
user = $1
date = $2
count&#91;user "," date]++
}
END {
for(key in count) {
split(key, parts, ",")
print parts&#91;1], parts&#91;2], count&#91;key]
}
}' user_log.txt

五、getline的高级用法

1. 从文件读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 读取配置文件
awk '
BEGIN {
while((getline line < "config.txt") > 0) {
if(line ~ /=/) {
split(line, kv, "=")
config&#91;kv&#91;1]] = kv&#91;2]
}
}
close("config.txt")
}
{
print $1, config&#91;"prefix"] $2
}' data.txt

2. 从管道读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 执行命令并读取输出
awk '
BEGIN {
cmd = "ls -l"
while((cmd | getline) > 0) {
if(NF > 8) files&#91;$NF] = $5 # 文件名和大小
}
close(cmd)
}
{
if($1 in files) {
print $1, files&#91;$1]
}
}' file_list.txt

六、输入输出控制

1. 输出重定向

1
2
3
4
5
6
7
8
9
10
11
12
13
# 输出到不同文件
awk '{
if($2 >= 60) {
print $0 > "pass.txt"
} else {
print $0 > "fail.txt"
}
}
END {
close("pass.txt")
close("fail.txt")
}' scores.txt

2. 格式化输出控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 控制输出格式
awk 'BEGIN {
OFS = "\t" # 输出字段分隔符
ORS = "\n---\n" # 输出记录分隔符
}
{
print $1, $2, $3
}' data.txt

# printf的高级用法
awk '{
printf "%-10s %8.2f %5d\n", $1, $2, $3
}' sales.txt

七、错误处理与调试

1. 错误检查

1
2
3
4
5
6
7
8
9
# 检查getline返回值
awk '{
if((getline line) <= 0) {
print "读取失败或文件结束" > "/dev/stderr"
exit 1
}
print line
}'

2. 调试技巧

1
2
3
4
5
6
7
8
9
# 使用print调试
awk '{
print "DEBUG: processing line", NR, "with", NF, "fields" > "/dev/stderr"
# 实际处理逻辑
}' data.txt

# 使用dump变量
awk -d 'BEGIN {var=1; print var}' # 会输出变量信息到文件

八、性能优化技巧

1. 避免重复计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 不好的做法
awk '{
if(length($1) > 10) { # 每次都计算长度
print $1
}
}'

# 好的做法
awk '{
len = length($1) # 只计算一次
if(len > 10) {
print $1
}
}'

2. 合理使用正则

1
2
3
4
5
6
# 避免复杂正则
awk '$0 ~ /^&#91;0-9]{4}-&#91;0-9]{2}-&#91;0-9]{2} &#91;0-9]{2}:&#91;0-9]{2}:&#91;0-9]{2}/'

# 简化为字符串比较(如果可能)
awk 'substr($0,1,19) ~ /^&#91;0-9 :-]+$/'

九、实用中级示例

1. 日志分析脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/awk -f
# 分析Apache访问日志
BEGIN {
FS = " "
print "IP地址\t\t访问次数\t流量总计"
}
{
ip = $1
bytes = ($10 == "-" ? 0 : $10)
count&#91;ip]++
total_bytes&#91;ip] += bytes
}
END {
for(ip in count) {
printf "%-15s\t%8d\t%10d\n", ip, count&#91;ip], total_bytes&#91;ip]
}
}

2. 数据透视表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 生成销售数据透视表
awk '
BEGIN {
FS = ","
print "产品\t一月\t二月\t三月\t总计"
}
NR > 1 {
product = $1
month = $2
sales = $3
monthly&#91;product,month] += sales
total&#91;product] += sales
}
END {
months&#91;"一月"] = "一月"; months&#91;"二月"] = "二月"; months&#91;"三月"] = "三月"
for(product in total) {
printf "%s", product
for(month in months) {
printf "\t%d", monthly&#91;product,month]
}
printf "\t%d\n", total&#91;product]
}
}' sales.csv

3. 配置文件解析器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 解析INI格式配置文件
awk '
BEGIN { section = "global" }
/^\&#91;.*\]$/ {
sub(/^\&#91;/, "");
sub(/\]$/, "");
section = $0;
next
}
/^&#91;a-zA-Z]/ && /=/ {
split($0, kv, "=");
config&#91;section "/" kv&#91;1]] = kv&#91;2]
}
END {
for(key in config) {
print key " = " config&#91;key]
}
}' config.ini

十、GNU AWK 扩展功能

1. 高精度计算

1
2
3
4
5
6
# 使用 -M 选项进行高精度计算
awk -M 'BEGIN {
print 1/3 # 精确到小数点后多位
print 2^100 # 大数计算
}'

2. 包含文件

1
2
3
4
5
6
7
8
9
10
11
# functions.awk
function square(x) { return x * x }
function cube(x) { return x * x * x }

# main.awk
@include "functions.awk"
BEGIN {
print square(5) # 25
print cube(3) # 27
}

3. 扩展库使用

1
2
3
4
5
# 使用JSON库(如果安装)
awk -l json 'BEGIN {
# JSON处理功能
}'

这些中级内容涵盖了 AWK 的核心中高级功能,掌握后可以处理更复杂的文本处理任务。

data-ad-format="auto" data-full-width-responsive="true">