AWK 中级学习手册

一、内置函数详解

1. 数值函数

# 常用数值函数
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. 字符串函数

# 字符串处理函数
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. 时间函数

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

4. 其他实用函数

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

二、自定义函数

1. 基本语法

function 函数名(参数列表) {
    函数体
    return 返回值
}

2. 实际示例

# 计算平均值函数
awk '
function avg(arr, n) {
    sum = 0
    for(i = 1; i <= n; i++) {
        sum += arr[i]
    }
    return sum / n
}

{
    scores[NR] = $2
}
END {
    print "平均分:", avg(scores, NR)
}' students.txt
# 字符串处理函数
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. 正则表达式操作符

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

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

2. match函数的高级用法

# 提取匹配内容
awk '{
    if(match($0, /[0-9]{4}-[0-9]{2}-[0-9]{2}/)) {
        date = substr($0, RSTART, RLENGTH)
        print "找到日期:", date
    }
}' logs.txt

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

四、多维数组处理

1. 模拟多维数组

# 使用分隔符模拟二维数组
awk '{
    matrix[NR,1] = $1
    matrix[NR,2] = $2
    matrix[NR,3] = $3
}
END {
    for(row = 1; row <= NR; row++) {
        for(col = 1; col <= 3; col++) {
            printf "%s\t", matrix[row,col]
        }
        print ""
    }
}' data.txt

2. 关联数组的复杂应用

# 统计每个用户在不同日期的操作次数
awk '{
    user = $1
    date = $2
    count[user "," date]++
}
END {
    for(key in count) {
        split(key, parts, ",")
        print parts[1], parts[2], count[key]
    }
}' user_log.txt

五、getline的高级用法

1. 从文件读取

# 读取配置文件
awk '
BEGIN {
    while((getline line < "config.txt") > 0) {
        if(line ~ /=/) {
            split(line, kv, "=")
            config[kv[1]] = kv[2]
        }
    }
    close("config.txt")
}
{
    print $1, config["prefix"] $2
}' data.txt

2. 从管道读取

# 执行命令并读取输出
awk '
BEGIN {
    cmd = "ls -l"
    while((cmd | getline) > 0) {
        if(NF > 8) files[$NF] = $5  # 文件名和大小
    }
    close(cmd)
}
{
    if($1 in files) {
        print $1, files[$1]
    }
}' file_list.txt

六、输入输出控制

1. 输出重定向

# 输出到不同文件
awk '{
    if($2 >= 60) {
        print $0 > "pass.txt"
    } else {
        print $0 > "fail.txt"
    }
}
END {
    close("pass.txt")
    close("fail.txt")
}' scores.txt

2. 格式化输出控制

# 控制输出格式
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. 错误检查

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

2. 调试技巧

# 使用print调试
awk '{
    print "DEBUG: processing line", NR, "with", NF, "fields" > "/dev/stderr"
    # 实际处理逻辑
}' data.txt

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

八、性能优化技巧

1. 避免重复计算

# 不好的做法
awk '{
    if(length($1) > 10) {  # 每次都计算长度
        print $1
    }
}'

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

2. 合理使用正则

# 避免复杂正则
awk '$0 ~ /^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/'

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

九、实用中级示例

1. 日志分析脚本

#!/usr/bin/awk -f
# 分析Apache访问日志
BEGIN {
    FS = " "
    print "IP地址\t\t访问次数\t流量总计"
}
{
    ip = $1
    bytes = ($10 == "-" ? 0 : $10)
    count[ip]++
    total_bytes[ip] += bytes
}
END {
    for(ip in count) {
        printf "%-15s\t%8d\t%10d\n", ip, count[ip], total_bytes[ip]
    }
}

2. 数据透视表

# 生成销售数据透视表
awk '
BEGIN {
    FS = ","
    print "产品\t一月\t二月\t三月\t总计"
}
NR > 1 {
    product = $1
    month = $2
    sales = $3
    monthly[product,month] += sales
    total[product] += sales
}
END {
    months["一月"] = "一月"; months["二月"] = "二月"; months["三月"] = "三月"
    for(product in total) {
        printf "%s", product
        for(month in months) {
            printf "\t%d", monthly[product,month]
        }
        printf "\t%d\n", total[product]
    }
}' sales.csv

3. 配置文件解析器

# 解析INI格式配置文件
awk '
BEGIN { section = "global" }
/^\[.*\]$/ { 
    sub(/^\[/, ""); 
    sub(/\]$/, ""); 
    section = $0; 
    next 
}
/^[a-zA-Z]/ && /=/ { 
    split($0, kv, "="); 
    config[section "/" kv[1]] = kv[2] 
}
END {
    for(key in config) {
        print key " = " config[key]
    }
}' config.ini

十、GNU AWK 扩展功能

1. 高精度计算

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

2. 包含文件

# 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. 扩展库使用

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

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

此条目发表在linux文章分类目录,贴了标签。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注