Awk 例程大全
📚 Awk 基础语法
awk 'pattern { action }' file awk -f script.awk file
🔧 常用选项
| 选项 | 说明 |
|---|
-F | 指定字段分隔符 |
-v | 定义变量 |
-f | 从文件读取 awk 脚本 |
-F',' | 指定逗号为分隔符 |
-F'[:\t]' | 多个分隔符 |
-F'\t' | 制表符分隔 |
📊 内置变量
| 变量 | 说明 | 示例值 |
|---|
NR | 当前行号 | 1, 2, 3... |
FNR | 当前文件行号 | 1, 2, 3... |
NF | 当前行的字段数 | 3, 4, 5... |
FS | 字段分隔符 | " ", "\t" |
OFS | 输出字段分隔符 | " ", "\t" |
RS | 记录分隔符 | "\n" |
ORS | 输出记录分隔符 | "\n" |
FILENAME | 当前文件名 | "data.txt" |
$0 | 整行内容 | "abc def ghi" |
$1, $2... | 第1,2...个字段 | "abc", "def" |
📝 基础例程
1.简单打印
# 打印整行 awk '{print}' file.txt awk '{print $0}' file.txt # 打印第一列 awk '{print $1}' file.txt # 打印多列 awk '{print $1, $3}' file.txt # 打印最后一列 awk '{print $NF}' file.txt # 打印倒数第二列 awk '{print $(NF-1)}' file.txt
2.条件过滤
# 打印第一列为 "apple" 的行 awk '$1 == "apple"' file.txt awk '$1 == "apple" {print}' file.txt # 打印数值大于100的行 awk '$2 > 100' file.txt # 打印包含 "error" 的行 awk '/error/' file.txt awk '$0 ~ /error/' file.txt # 打印不包含 "error" 的行 awk '!/error/' file.txt # 多个条件 awk '$1 == "apple" && $2 > 10' file.txt awk '$1 == "apple" || $1 == "banana"' file.txt
3.字段处理
# 自定义输出格式 awk '{print "列1:", $1, "列3:", $3}' file.txt # 重新排列列 awk '{print $3, $1, $2}' file.txt # 计算并添加新字段 awk '{print $1, $2, $2*1.1}' file.txt # 添加行号 awk '{print NR, $0}' file.txt # 添加文件名 awk '{print FILENAME ":", $0}' file.txt
🎯 数据处理
1.数值计算
# 求和(第二列) awk '{sum += $2} END {print "总和:", sum}' file.txt # 平均值 awk '{sum += $2; count++} END {print "平均:", sum/count}' file.txt # 最大值 awk 'NR==1 {max=$2} $2>max {max=$2} END {print "最大值:", max}' file.txt # 最小值 awk 'NR==1 {min=$2} $2<min {min=$2} END {print "最小值:", min}' file.txt # 统计行数 awk 'END {print "总行数:", NR}' file.txt awk 'END {print "总行数:", FNR}' file.txt # 单个文件
2.分组统计
# 按第一列分组求和第二列 awk '{sum[$1] += $2} END {for (i in sum) print i, sum[i]}' file.txt # 按第一列分组计数 awk '{count[$1]++} END {for (i in count) print i, count[i]}' file.txt # 按第一列分组求平均值 awk '{sum[$1] += $2; count[$1]++} END {for (i in sum) print i, sum[i]/count[i]}' file.txt # 分组并排序输出 awk '{sum[$1] += $2} END {for (i in sum) print i, sum[i] | "sort -k2,2nr"}' file.txt
3.文本处理
# 计算每行单词数 awk '{print NF, $0}' file.txt # 计算文件总单词数 awk '{total += NF} END {print total}' file.txt # 查找最长行 awk 'length($0) > max {max = length($0); line = $0} END {print max, line}' file.txt # 反转行顺序 awk '{lines[NR] = $0} END {for (i=NR; i>0; i--) print lines[i]}' file.txt
🔄 控制结构
1.if-else
# 简单判断 awk '{if ($2 > 100) print $1, "高价"; else print $1, "正常"}' file.txt # 条件运算符 awk '{print $1, ($2 > 100 ? "高价" : "正常")}' file.txt # 多条件判断 awk '{ if ($2 > 200) grade = "A" else if ($2 > 100) grade = "B" else grade = "C" print $1, grade }' file.txt
2.循环
# for 循环 awk '{for (i=1; i<=NF; i++) print "字段", i, ":", $i}' file.txt # while 循环 awk '{i=1; while (i<=NF) {print "字段", i, ":", $i; i++}}' file.txt # 数组遍历 awk '{for (i=1; i<=NF; i++) count[$i]++} END {for (word in count) print word, count[word]}' file.txt
3.数组操作
# 检查键是否存在 awk '{if (!($1 in seen)) {print $1; seen[$1] = 1}}' file.txt # 多维数组(模拟) awk '{data[$1,$2] = $3} END {for (i in data) print i, data[i]}' file.txt # 数组排序输出 awk '{arr[NR] = $0} END { n = asort(arr) for (i=1; i<=n; i++) print arr[i] }' file.txt
📈 高级数据处理
1.CSV/TSV 处理
# CSV 处理(处理带逗号的字段) awk -F',' '{ gsub(/"/, "") # 去除引号 print $1, $3 }' data.csv # TSV 处理 awk -F'\t' '{print $1, $3}' data.tsv # 处理带标题的 CSV awk -F',' 'NR==1 {split($0, headers); next} {print headers[1], $1}' data.csv
2.日志分析
# 提取IP和访问次数 awk '{ip = $1; count[ip]++} END {for (i in count) print i, count[i]}' access.log # 分析HTTP状态码 awk '{status = $9; codes[status]++} END {for (c in codes) print c, codes[c]}' access.log # 统计每小时请求量 awk '{split($4, t, ":"); hour = t[2]; requests[hour]++} END {for (h in requests) print h, requests[h]}' access.log
3.JSON处理(简单)
# 提取简单JSON值 echo '{"name":"John","age":30}' | awk -F'"' '{print $4, $8}' # 处理每行一个JSON对象 awk -F'"' '{ for (i=1; i<=NF; i++) { if ($i == "name") print $(i+2) if ($i == "age") print $(i+2) } }' data.json
🛠️ 实用脚本
1.文件处理
# 批量重命名助手 ls *.txt | awk '{print "mv \"" $0 "\" \"" substr($0, 1, length($0)-4) ".md\""}' # 文件大小统计 ls -l | awk 'NR>1 {sum += $5; files[NR] = $9} END {print "总大小:", sum, "文件数:", NR-1}' # 查找重复文件(基于大小) find . -type f -exec ls -l {} \; | awk '{size = $5; count[size]++; if (count[size]==2) print "发现重复大小:", size}'
2.系统监控
# 进程内存统计 ps aux | awk 'NR>1 {user[$1] += $4} END {for (u in user) print u, user[u] "%"}' # 磁盘使用分析 df -h | awk 'NR>1 {print $1, $5, $6}' # 网络连接统计 netstat -an | awk '/^tcp/ {state[$6]++} END {for (s in state) print s, state[s]}'
3.文本分析
# 单词频率统计 awk '{ gsub(/[.,!?;:"]/, "") # 去除标点 for (i=1; i<=NF; i++) { word = tolower($i) freq[word]++ } } END { for (w in freq) print freq[w], w | "sort -nr" }' text.txt # 提取电子邮件地址 awk '{ for (i=1; i<=NF; i++) { if ($i ~ /@/) { print $i } } }' file.txt
🧩 高级技巧
1.BEGIN 和 END 块
# 初始化 awk 'BEGIN { FS = "," OFS = "\t" print "开始处理..." } {print $1, $2} END { print "处理完成,共处理", NR, "行" }' data.csv
2.自定义函数
awk ' function add(a, b) { return a + b } function multiply(a, b) { return a * b } { sum = add($1, $2) product = multiply($1, $2) print $1, $2, "和:", sum, "积:", product } ' numbers.txt
3.多文件处理
# 处理多个文件 awk '{print FILENAME, NR, $0}' file1.txt file2.txt # 每个文件独立统计 awk '{count[FILENAME]++} END {for (f in count) print f, count[f]}' *.txt # 文件间数据关联 awk 'FNR==NR {data[$1] = $2; next} $1 in data {print $0, data[$1]}' file1.txt file2.txt
4.模式范围
# 范围模式 awk '/start_pattern/,/end_pattern/' file.txt # 范围内处理 awk '/start/,/end/ {print NR, $0}' file.txt # 排除范围 awk '!(/start/,/end/)' file.txt
📋 实用单行命令
1.数据转换
# 列转行 awk '{for (i=1; i<=NF; i++) print $i}' file.txt # 行转列(每3个字段一行) awk '{for (i=1; i<=NF; i++) printf "%s%s", $i, (i%3==0 ? "\n" : "\t")}' file.txt # 转置矩阵 awk '{for (i=1; i<=NF; i++) matrix[NR,i] = $i} END {for (j=1; j<=NF; j++) {for (i=1; i<=NR; i++) printf "%s\t", matrix[i,j]; print ""}}' matrix.txt
2.格式美化
# 添加千位分隔符 echo "1234567" | awk '{while (match($0, /[0-9][0-9][0-9][0-9]+/)) {sub(/[0-9][0-9][0-9][0-9]+/, "," substr($0, RSTART, RLENGTH-3) "," substr($0, RSTART+RLENGTH-3, 3))} print $0}' # 右对齐数字 awk '{printf "%10s %10s\n", $1, $2}' file.txt # 创建表格 awk 'BEGIN {printf "%-20s %-10s %-10s\n", "名称", "价格", "数量"} {printf "%-20s %-10.2f %-10d\n", $1, $2, $3}' data.txt
3.数据验证
# 检查IP地址格式 awk '$1 !~ /^([0-9]{1,3}\.){3}[0-9]{1,3}$/ {print "Invalid IP:", $1}' log.txt # 检查邮箱格式 awk '$2 !~ /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ {print "Invalid email:", $2}' users.txt # 检查数值范围 awk '$3 < 0 || $3 > 100 {print "Out of range:", $0}' scores.txt
🎪 复杂例程
1.报表生成
awk -F',' 'BEGIN { print "销售报告" print "==========" print "日期 销售人员 销售额" print "--------------------------------" } { date = $1 salesperson = $2 amount = $3 daily_total[date] += amount person_total[salesperson] += amount person_sales[date,salesperson] += amount } END { print "\n按日期汇总:" for (d in daily_total) { printf "%s: %.2f\n", d, daily_total[d] } print "\n按销售人员汇总:" for (p in person_total) { printf "%s: %.2f\n", p, person_total[p] } print "\n详细数据:" for (key in person_sales) { split(key, keys, SUBSEP) printf "%s - %s: %.2f\n", keys[1], keys[2], person_sales[key] } }' sales.csv
2.数据清洗
awk -F',' 'BEGIN { OFS = "," print "id,name,age,email,status" } NR == 1 {next} # 跳过标题 { # 清理数据 gsub(/^\s+|\s+$/, "", $1) # 去除首尾空格 gsub(/\s+/, " ", $2) # 合并多个空格 $3 = int($3) # 年龄转为整数 gsub(/[^a-zA-Z0-9._%+-@]/, "", $4) # 清理邮箱 $5 = toupper($5) # 状态转大写 # 数据验证 if ($3 < 0 || $3 > 150) $3 = "NULL" if ($4 !~ /@/) $4 = "INVALID" if ($5 !~ /^(ACTIVE|INACTIVE|PENDING)$/) $5 = "UNKNOWN" # 输出清理后的数据 print $1, $2, $3, $4, $5 }' raw_data.csv > cleaned_data.csv
3.监控脚本
#!/bin/bash # 监控系统资源的awk脚本 # 监控CPU使用率 top -bn1 | awk '/^%Cpu/ { idle = $8 usage = 100 - idle printf "CPU使用率: %.1f%%\n", usage if (usage > 80) print "警告: CPU使用率过高!" }' # 监控内存 free -m | awk 'NR==2 { total = $2 used = $3 free = $4 ratio = used/total*100 printf "内存: 已用 %dM/总共 %dM (%.1f%%)\n", used, total, ratio if (ratio > 90) print "警告: 内存不足!" }' # 监控磁盘 df -h | awk '$6 == "/" { use = $5 sub(/%/, "", use) printf "磁盘使用率: %s%%\n", use if (use > 90) print "警告: 磁盘空间不足!" }'
📚 学习资源
1.调试技巧
# 打印调试信息 awk '{print "DEBUG: NR=" NR, "NF=" NF, "$1=" $1 > "/dev/stderr"}' file.txt # 使用-v调试 awk -v debug=1 '{if (debug) print "Processing:", $0} {print $1}' file.txt
2.性能优化
# 1. 避免重复计算 awk '{key = $1; count[key]++}' # 好 awk '{count[$1]++}' # 更好 # 2. 使用内置函数 awk '{print length($0)}' # 使用length()而不是自己计算 # 3. 减少数组使用 # 如果可能,使用变量而不是数组
3.最佳实践
# 1. 总是引用字段 awk '{print $1}' # 好 awk '{print $1, $2}' # 更好,清晰的字段引用 # 2. 使用合适的变量名 awk '{total += $2} END {print total}' # 好 awk '{sum += $2} END {print sum}' # 更好,描述性变量名 # 3. 添加注释 awk ' # 计算平均价格 {sum += $2; count++} # 累加总和和计数 # 输出结果 END { print "平均价格:", sum/count } ' prices.txt
🎓 速查表
常用模式
# 空行 /^$/ /^\s*$/ # 注释行 /^#/ /^[[:space:]]*#/ # 数字 /^[0-9]+$/ /^[0-9]+\.[0-9]+$/ # 电子邮件 /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/ # IP地址 /([0-9]{1,3}\.){3}[0-9]{1,3}/
常用函数
# 字符串函数 length(str) # 字符串长度 substr(str, start, len) # 子字符串 index(str, substr) # 查找子串位置 split(str, arr, sep) # 分割字符串 tolower(str) # 转小写 toupper(str) # 转大写 gsub(regex, repl, str) # 全局替换 sub(regex, repl, str) # 替换第一个 # 数学函数 int(num) # 取整 sqrt(num) # 平方根 exp(num) # 指数 log(num) # 对数 sin(num), cos(num), atan2(y, x) # 三角函数 # 时间函数 systime() # 当前时间戳 strftime(format, timestamp) # 格式化时间
这个大全涵盖了 awk 从基础到高级的绝大多数用法。掌握这些例程,你就能轻松处理各种文本和数据处理的挑战!