面对复杂的日志分析和报表生成需求,awk让你像写程序一样处理文本,实现Excel级别的数据分析。
什么是awk?
awk是一种强大的文本处理编程语言,由Alfred Aho、Peter Weinberger和Brian Kernighan在1977年创建(名字取自三人姓氏首字母)。
与grep(搜索)和sed(替换)不同,awk是一个完整的编程环境:
简单来说:grep和sed能做的,awk都能做;awk能做的,grep和sed不一定能做。
为什么awk是"第三驾马车"?
awk在Linux文本处理工具链中处于顶端:
awk的定位:当grep和sed无法满足需求时,awk就是你的终极武器。
awk核心概念
1. 执行模式:模式-动作
awk程序由一系列模式-动作对组成:
awk '模式 { 动作 }' 文件
- • 动作:对匹配行执行的操作(可选,默认打印整行)
# 示例:打印包含"error"的行awk '/error/ { print }' app.log# 示例:打印第3行awk 'NR==3 { print }' file.txt# 示例:打印所有行(无模式,默认匹配所有)awk '{ print }' file.txt
2. 字段分割
awk最强大的特性是自动字段分割:
# 默认按空白字符分割,$1表示第1个字段,$2表示第2个字段...awk '{ print $1, $2 }' data.txt# 指定分隔符(如逗号)awk -F',' '{ print $1, $3 }' data.csv# $0表示整行,NF表示字段数awk '{ print "字段数:", NF, "内容:", $0 }' data.txt
3. 内置变量
| |
|---|
$0 | |
$1, $2, ... | |
NF | |
NR | |
FS | |
OFS | |
RS | |
ORS | |
awk基础用法(15分钟上手)
1. 打印指定字段
# 打印第1和第3列awk '{ print $1, $3 }' data.txt# 打印最后一列awk '{ print $NF }' data.txt# 自定义输出格式awk '{ print "Name:", $1, "Score:", $2 }' scores.txt
2. 条件过滤
# 打印第2列大于100的行awk '$2 > 100 { print }' data.txt# 打印第3列等于"ERROR"的行awk '$3 == "ERROR" { print }' app.log# 打印包含"timeout"的行(正则匹配)awk '/timeout/ { print }' app.log
3. 计算统计
# 计算第2列的总和awk '{ sum += $2 } END { print "Total:", sum }' data.txt# 计算平均值awk '{ sum += $2; count++ } END { print "Average:", sum/count }' data.txt# 求最大值和最小值awk 'NR==1 { max=$2; min=$2 } { if($2>max) max=$2; if($2<min) min=$2 } END { print "Max:", max, "Min:", min }' data.txt
4. 格式化输出
# 类似C语言的printf格式化awk '{ printf "%-10s %5d\n", $1, $2 }' data.txt# 生成报表awk 'BEGIN { print "Name\tScore"; print "----\t-----" } { print $1"\t"$2 }' scores.txt
awk进阶技巧(数据分析利器)
技巧1:多文件处理
# 同时处理多个文件,用FILENAME区分来源awk '{ print FILENAME, $0 }' file1.txt file2.txt# 对多个文件分别统计行数awk 'ENDFILE { print FILENAME, FNR }' *.log
技巧2:关联数组(字典)
# 统计每个IP出现的次数awk '{ count[$1]++ } END { for(ip in count) print ip, count[ip] }' access.log# 按用户统计交易额awk '{ amount[$1] += $3 } END { for(user in amount) print user, amount[user] }' transactions.txt
技巧3:字符串处理
# 字符串长度awk '{ print length($1) }' names.txt# 子串提取awk '{ print substr($1, 1, 3) }' data.txt# 字符串替换awk '{ gsub(/old/, "new"); print }' file.txt# 分割字符串awk '{ split($0, arr, ","); print arr[1], arr[2] }' csv.txt
技巧4:条件判断和循环
# if-else条件awk '{ if($2 >= 90) grade="A"; else if($2 >= 80) grade="B"; else grade="C"; print $1, grade }' scores.txt# for循环awk 'BEGIN { for(i=1; i<=5; i++) print i }'# while循环awk '{ i=1; while(i<=NF) { print $i; i++ } }' data.txt
技巧5:自定义函数
awk 'function square(x) { return x * x}{ print $1, square($2)}' data.txt
实战场景:工作中的awk应用
场景1:日志分析报表
# 统计每小时的请求量awk -F'[ :]' '{ hour=$5; count[hour]++ } END { for(h in count) print h":00", count[h] }' access.log | sort# 统计各状态码数量awk '$9 ~ /^[0-9]+$/ { code[$9]++ } END { for(c in code) print c, code[c] }' access.log# 统计响应时间分布awk '$10 > 0 { if($10 < 100) bucket["<100ms"]++; else if($10 < 500) bucket["100-500ms"]++; else bucket[">500ms"]++ } END { for(b in bucket) print b, bucket[b] }' access.log
场景2:数据清洗与转换
# CSV转JSON(简单版)awk -F',' 'NR>1 { printf "{\"name\":\"%s\",\"age\":%s}\n", $1, $2 }' data.csv# 提取特定列并排序awk '{ print $2, $1 }' data.txt | sort -rn | head -10# 合并多行数据awk '{ printf "%s%s", $0, (NR%3==0?"\n":",") }' data.txt
场景3:系统监控报表
# 分析top命令输出,找出内存占用最高的进程top -bn1 | awk 'NR>7 { print $10, $12 }' | sort -rn | head -5# 统计各用户的进程数ps aux | awk 'NR>1 { user[$1]++ } END { for(u in user) print u, user[u] }'# 磁盘使用报表df -h | awk 'NR>1 { print $5, $6 }' | sort -rn | head -5
场景4:业务数据统计
# 计算每日销售额(假设日志格式:日期 金额)awk '{ day=$1; sales[day] += $2 } END { for(d in sales) print d, sales[d] }' sales.log | sort# 找出购买次数最多的用户awk '{ user[$1]++ } END { max=0; for(u in user) if(user[u]>max) { max=user[u]; top=u } print top, max }' orders.txt# 计算客单价awk '{ user[$1]++; amount[$1] += $2 } END { for(u in user) print u, amount[u]/user[u] }' transactions.txt
awk与grep、sed的配合
黄金组合:grep + awk
# 先过滤再分析grep "ERROR" app.log | awk '{ print $1, $2 }' | sort | uniq -c | sort -rn
黄金组合:sed + awk
# 先清洗再统计sed 's/[^0-9a-zA-Z ]//g' data.txt | awk '{ count[$1]++ } END { for(w in count) print count[w], w }' | sort -rn | head -20
三驾马车联合作战
# 完整的数据处理流水线cat access.log | \ grep "api/v1/order" | \ sed 's/.*user_id=\([0-9]*\).*/\1/' | \ awk '{ users[$1] = 1 } END { print "Unique users:", length(users) }'
awk vs 其他工具
常见问题解答
Q: awk和gawk有什么区别?
A: gawk是GNU版本的awk,功能更强大。Linux系统通常默认安装gawk。
# 检查版本awk --version
Q: 如何处理包含空格的字段?
A: 使用-F指定分隔符,或用正则表达式:
# 使用逗号分隔awk -F',' '{ print $2 }' data.csv# 使用多个空格分隔awk -F' +' '{ print $1 }' data.txt
Q: 如何在awk中使用shell变量?
A: 使用-v参数传递:
threshold=100awk -v t=$threshold '$2 > t { print }' data.txt
Q: awk能处理Excel文件吗?
A: 不能直接处理。需要先将Excel转为CSV:
# 使用其他工具转换后,再用awk处理libreoffice --headless --convert-to csv data.xlsxawk -F',' '{ print $1 }' data.csv
学习建议
- 3. 学会使用BEGIN/END:初始化和收尾操作
总结
awk作为Linux三驾马车之三,是文本处理的终极武器:
记住:当grep和sed无法解决问题时,awk就是你的答案。
三驾马车对比总结
黄金法则:
- • 不确定?先用 grep 定位,再用 sed/awk 处理
上一篇:《Linux三驾马车之二:sed命令,文本编辑的自动化神器》
本文是Linux三驾马车系列第三篇(完结篇),感谢阅读! #linux #三驾马车 #grep #sed #awk #文本处理编辑语言 #数据分析 #数据处理