awk是Linux/Unix系统中最强大的文本处理工具之一,它结合了模式匹配、字段处理、流程控制和格式化输出等功能,特别适合处理结构化文本数据(如日志文件、CSV、配置文件等)。awk的名字取自其三位创始人的姓氏首字母:Aho、Weinberger和Kernighan。
awk的工作方式是逐行读取文件,对每行应用指定的模式匹配和动作。它默认以空白字符作为字段分隔符,内置丰富的变量和函数,支持算术运算和关联数组。掌握awk是进行文本分析、数据提取和报告生成的核心技能。
1. 基本用法
| 命令 | 说明 |
|---|
awk '{print}' file.txt | |
awk '{print $1}' file.txt | |
awk '{print $1, $3}' file.txt | |
awk 'NR==1{print}' file.txt | |
awk 'NR>1{print}' file.txt | |
awk 'END{print}' file.txt | |
2. 字段分隔符
| 命令 | 说明 |
|---|
awk -F ':' '{print $1}' /etc/passwd | |
awk -F ',' '{print $2}' file.csv | |
awk -F '\t' '{print $1}' file.tsv | |
awk -F '[ :]' '{print $1}' file.txt | |
awk 'BEGIN{FS="|"} {print $2}' file.txt | |
awk -F ':' 'BEGIN{OFS=","} {print $1,$3}' /etc/passwd | |
3. 模式匹配
| 命令 | 说明 |
|---|
awk '/error/ {print}' app.log | |
awk '/^ERROR/ {print}' app.log | |
awk '$3 > 100 {print}' file.txt | |
awk '$1 == "root" {print}' /etc/passwd | |
awk 'NF == 3 {print}' file.txt | |
awk 'NF > 0 {print}' file.txt | |
awk 'NR >= 10 && NR <= 20' file.txt | |
awk '$2 ~ /^[0-9]+$/ {print}' file.txt | |
4. 计算与统计
| 命令 | 说明 |
|---|
awk '{sum += $2} END {print sum}' file.txt | |
awk '{sum += $2} END {print sum/NR}' file.txt | |
awk '{count++} END {print count}' file.txt | |
awk '{sum += $2} END {print "Total:", sum}' file.txt | |
awk 'BEGIN{print 5*7}' | |
awk '$2 > 0 {print $1, $2*1.2}' file.txt | |
awk '{print sqrt($1)}' file.txt | |
awk '{print int($1)}' file.txt | |
5. 输出格式化
| 命令 | 说明 |
|---|
awk '{printf "%s\t%s\n", $1, $2}' file.txt | |
awk '{printf "%-20s %s\n", $1, $2}' file.txt | |
awk '{printf "%10s %10s\n", $1, $2}' file.txt | |
awk '{printf "%.2f\n", $1}' file.txt | |
awk 'BEGIN{OFS=","} {print $1,$2}' file.txt | |
awk 'BEGIN{ORS="\r\n"} {print $0}' file.txt | |
6. 内置变量
| 变量 | 说明 |
|---|
NR | |
NF | |
FNR | |
FS | |
RS | |
OFS | |
ORS | |
FILENAME | |
$0 | |
$NF | |
$(NF-1) | |
7. 字符串函数
| 函数 | 说明与示例 |
|---|
length(s) | |
substr(s, start, n) | |
split(s, arr, sep) | |
sub(regex, repl, s) | |
gsub(regex, repl, s) | |
index(s, t) | |
match(s, regex) | |
tolower(s) | |
toupper(s) | |
8. 数组操作
awk的数组是关联数组(键可以是字符串):
| 语法 | 说明 |
|---|
arr[key] = val | |
arr[key] | |
for (k in arr) { ... } | |
if (key in arr) { ... } | |
delete arr[key] | |
delete arr | |
示例:
# 统计字段出现次数
awk '{count[$1]++} END {for (word in count) print word, count[word]}' file.txt
# 去重(保留首次出现顺序)
awk '!seen[$0]++' file.txt
9. 控制流语句
| 语法 | 说明 |
|---|
if (cond) { ... } | |
if (cond) { ... } else { ... } | |
for (i=1; i<=n; i++) { ... } | |
for (k in arr) { ... } | |
while (cond) { ... } | |
do { ... } while (cond) | |
next | |
exit | |
10. 实用组合模式
| 命令 | 说明 |
|---|
awk -F: '{print $1}' /etc/passwd | sort | |
ps aux | awk '$3 > 50 {print $2, $3, $11}' | |
df -h | awk 'NR>1 {print $5, $6}' | sed 's/%//' | |
awk '{print NF, $0}' file.txt | sort -rn | head | |
awk '!seen[$0]++' file.txt | |
awk '{a[i++]=$0} END {for(j=i-1; j>=0; j--) print a[j]}' file.txt | |
awk -v name="root" '$1 == name {print}' /etc/passwd | |
awk '{if(NR==1) print "Header"; print}' file.txt | |
11. 常用选项速查
| 选项 | 完整名称 | 说明 |
|---|
-F | | |
-v | | |
-f | | |
-e | | |
-E | | |
-b | | |
-W interactive | | |
--posix | | |
--dump-variables | | |
--profile | | |
12. awk vs sed vs cut 对比
13. 故障排查
| 问题 | 解决方法 |
|---|
| 字段分隔符不生效 | 确认分隔符是否正确(Tab用\t表示);使用-F或FS |
| print输出无内容 | |
| 数字比较不工作 | 确保字段是数字(非数字可能被当作0);使用$1+0强制转换 |
| BEGIN/END块不执行 | BEGIN在处理文件前执行,END在文件处理完后执行;无文件时可能不执行END |
| 数组遍历顺序不可控 | awk数组遍历是无序的;如需排序,先用asort()或管道到sort |
| 大文件处理慢 | 减少每行处理复杂度;使用更简单的工具如cut/grep |
| printf格式错误 | |
| 正则表达式不匹配 | 使用$0 ~ /pattern/显式匹配;检查正则语法 |
温馨提示: awk是文本处理的瑞士军刀。建议掌握以下模式:1)awk '{print $NF}'提取最后一列;2)awk '!seen[$0]++'去重;3)awk '{sum+=$1} END {print sum}'求和;4)awk -F: '$3>=1000 {print $1}' /etc/passwd查找普通用户;5)awk 'NR%2==0'打印偶数行。学习awk的最佳方式是先从简单的单行命令开始,逐步加入条件判断和循环。对于复杂的数据处理任务,可以将awk脚本写入.awk文件,使用-f执行。在大型日志分析场景中,awk经常与sort、uniq、grep等工具配合使用,形成强大的数据处理管道。