AWK文本处理完全指南
AWK概述
AWK是Unix/Linux环境中一款强大的文本处理工具,它本质上是一门专为数据扫描、过滤和报告生成而设计的编程语言。AWK可以从标准输入、文件或其他命令的输出中读取数据。与grep和sed并称为Shell编程三剑客。
AWK的名称源自三位创始人的姓氏首字母:Alfred Aho、Brian Kernighan和Peter Weinberger。在Linux系统中,默认使用的gawk(GNU AWK)是其增强版本,通常系统会创建符号链接将awk指向gawk。
核心功能
- 逐行扫描文本,支持模式匹配与条件过滤
- 数据统计与分析,如计算网站访问量、IP数量
- 支持条件判断、循环控制语句
- 提供格式化输出能力
基本用法
awk [选项] '模式[动作]' 文件...
awk [选项] '脚本' 变量=值 文件...
常用参数
-F:指定字段分隔符-v:定义或修改内部变量-f:从脚本文件读取AWK命令
工作原理
- AWK逐行读取文件,每行存储在内部变量
$0中 - 默认以空格或制表符作为字段分隔符,将行分解为多个字段
- 字段存储在编号变量中,
$1、$2等代表第1、2个字段 - 处理完一行后读取下一行,重复此过程直到文件末尾
内置变量
FS - 字段分隔符(默认空格或制表符)
NF - 当前行字段数量
NR - 当前行号
$0 - 当前行完整内容
$n - 当前行第n个字段
实用示例
基础打印
# 打印文件所有行
awk '{print}' test.txt
# 以冒号分隔,打印第1列
awk -F: '{print $1}' /etc/passwd
# 打印多列,使用逗号分隔
awk '{print $4, $5}' data.txt
BEGIN与END模式
# BEGIN在读取文件前执行
awk 'BEGIN{print "开始处理"} {print $0}' data.txt
# END在所有数据读取后执行
awk '{total+=$1} END{print "总和:", total}' numbers.txt
# 组合使用
awk 'BEGIN{sum=0} {sum+=$1} END{print "总计:", sum}' scores.txt
变量引用与运算
# 变量定义与运算
awk 'BEGIN{x=10; print x+1}'
awk 'BEGIN{print 2**3}' # 幂运算
# 从shell传递变量
name="admin"
awk -v user=$name 'BEGIN{print user}'
内置变量应用
# 显示行号和字段数
awk -F: '{print "第"NR"行有"NF"列"}' /etc/passwd
# 提取最后字段
awk -F: '{print $NF}' /etc/passwd
# 多文件处理时使用FNR
awk '{print FNR, $0}' file1 file2
输出分隔符自定义
awk -F: -v OFS=" | " '{print $1, $NF}' /etc/passwd
模式匹配
关系运算符
# 等于比较
awk -F: '$3==0 {print $1}' /etc/passwd
# 范围匹配
awk -F: 'NR>=5 && NR<=10' /etc/passwd
# 模糊匹配
awk -F: '$1 ~ /root/ {print $0}' /etc/passwd
awk -F: '$7 !~ /nologin$/' /etc/passwd
正则模式
# 查找以ro开头的行
awk '/^ro/' /etc/passwd
# 查找包含/sbin/bash的行(需转义)
awk '/\/bin\/bash/' /etc/passwd
行范围模式
# 从"开始"行到"结束"行
awk '/^daemon/,/^halt/' /etc/passwd
# 从NR=3到NR=6
awk 'NR==3,NR==6' data.txt
流程控制
条件判断
# if-else结构
awk -F: '{if($3==0) {print $1"是管理员"} else {print $1"非管理员"}}' /etc/passwd
# if-else if-else链
awk -F: '{
if($3==0) print "管理员"
else if($3>999) print "普通用户"
else print "系统用户"
}' /etc/passwd
循环控制
# for循环
awk 'BEGIN{for(i=1;i<=5;i++) print i}'
# while循环
awk 'BEGIN{i=1; while(i<=5) {print i; i++}}'
# 遍历数组
awk '{count[$1]++} END{for(ip in count) print ip, count[ip]}' access.log
数组应用
# 统计IP出现次数
awk '{ipCount[$1]++} END{for(ip in ipCount) print ip, ipCount[ip]}' access.log
# 统计用户名出现频次
awk '{for(i=1;i<=NF;i++) wordCount[$i]++}
END{for(w in wordCount) print w, wordCount[w]}' names.txt
# 删除数组元素
awk 'BEGIN{arr["a"]=1; delete arr["a"]}'
内置函数
数学函数
# 随机数生成
awk 'BEGIN{srand(); print rand()}'
# 生成1-100随机整数
awk 'BEGIN{srand(); print int(100*rand())}'
字符串函数
# 替换操作
awk '{gsub("old","new"); print}' data.txt
# 字符串长度
awk '{print length($1)}' data.txt
# 字符串切割
awk '{split($0, arr, ":"); print arr[1], arr[2]}' data.txt
# 子串位置
awk '{print index($0, "target")}' data.txt
高阶技巧
三元运算
awk -F: '{type=($3>999)?"普通用户":"系统用户"; print $1, type}' /etc/passwd
打印奇偶行
# 奇数行
awk 'i=!i' file.txt
# 偶数行
awk '!(i=!i)' file.txt
与Shell命令交互
# 通过双引号执行Shell命令
awk 'BEGIN{system("date")}'
# 管道传递数据
awk '{print | "sort -rn"}' data.txt
经典案例
分析Nginx访问日志
# 统计IP访问次数
awk '{ip[$1]++} END{for(i in ip) print i, ip[i]}' access.log
# 统计状态码分布
awk '{code[$9]++} END{for(c in code) print c, code[c]}' access.log
# 查找404错误最多的IP
awk '$9=="404" {ip[$1]++} END{for(i in ip) print i, ip[i]}' access.log | sort -k2 -rn | head
系统监控
# 查看内存使用率
free -m | awk '/Mem:/ {print int($3/$2*100)"%"}'
# 查看CPU空闲率
top -b -n1 | awk '/Cpu/ {print $8}'
文件合并
# 按第一列合并两个文件
awk 'FNR==NR{a[$1]=$0; next} {print a[$1], $2}' file1 file2
统计费用
# 统计各部门总支出与次数
awk '{dept[$1]++; cost[$1]+=$2}
END{for(d in dept) print d, cost[d], dept[d]}' expense.txt