linux awk文本处理:从字段提取到日志统计
linux awk
awk 是 Linux / Unix 系统中非常强大的文本处理工具,常用于日志分析、数据清洗、字段提取、统计汇总、报表生成等场景。它既可以作为命令行工具快速处理文本,也可以编写较复杂的脚本完成结构化数据处理。
一、awk 的基本语法
awk 的基本格式如下:
awk '条件 { 动作 }' 文件名
也可以写成:
awk 'pattern { action }' file
其中:
pattern:匹配条件,可以省略。action:满足条件后执行的动作,例如打印、计算、替换等。file:要处理的文件。
例如,打印文件每一行:
awk '{ print }' test.txt
{ print } 是动作,表示对每一行执行打印操作。
二、按字段处理数据
awk 默认以空白字符作为分隔符,包括空格、Tab 等。每一行会被自动拆分成多个字段:
| 变量 | 含义 |
|---|---|
$0 |
当前整行 |
$1 |
第 1 个字段 |
$2 |
第 2 个字段 |
$3 |
第 3 个字段 |
$NF |
最后一个字段 |
NF |
当前行字段数量 |
NR |
当前处理的总行号 |
例如,查看 /etc/passwd 文件中的用户名:
awk -F: '{ print $1 }' /etc/passwd
这里 -F: 表示使用冒号 : 作为字段分隔符。
也可以这样写:
awk 'BEGIN { FS=":" } { print $1 }' /etc/passwd
三、打印指定字段
假设有一个文件 students.txt:
Tom 90 85 88
Jerry 76 92 80
Alice 95 88 91
打印每行第 1 列和第 2 列:
awk '{ print $1, $2 }' students.txt
输出:
Tom 90
Jerry 76
Alice 95
如果想自定义输出分隔符,可以使用 OFS:
awk 'BEGIN { OFS="|" } { print $1, $2 }' students.txt
输出:
Tom|90
Jerry|76
Alice|95
四、条件过滤
awk 可以根据字段内容进行过滤。
例如,只打印第 2 列大于 80 的行:
awk '$2 > 80 { print $0 }' students.txt
也可以打印满足条件的姓名和分数:
awk '$2 > 80 { print $1, $2 }' students.txt
多个条件可以组合:
awk '$2 > 80 && $3 > 85 { print $1 }' students.txt
含义是:第 2 列大于 80,并且第 3 列大于 85。
五、统计计算
awk 很适合做统计。例如统计学生总分:
awk '{ sum = $2 + $3 + $4; print $1, sum }' students.txt
如果要统计所有学生第 2 列的总分和平均值:
awk '{ sum += $2; count++ } END { print "sum=", sum, "avg=", sum/count }' students.txt
其中:
sum += $2:累加第 2 列。count++:统计行数。END:在所有行处理完成后执行。
六、BEGIN 和 END 的作用
awk 中有两个常用特殊代码块:
1. BEGIN
BEGIN 在处理文件内容之前执行,常用于初始化变量、设置分隔符。
awk 'BEGIN { FS=","; OFS="|" } { print $1, $2 }' data.csv
2. END
END 在所有内容处理完成后执行,常用于输出统计结果。
awk 'END { print "总行数:", NR }' test.txt
七、字符串处理
awk 支持常见的字符串操作,例如替换、分割、匹配等。
1. 替换字符串
将字段中的 abc 替换为 xyz:
awk '{ gsub(/abc/, "xyz"); print }' test.txt
gsub 表示全局替换,会替换所有匹配内容。
如果只替换第一个匹配项,可以使用 sub:
awk '{ sub(/abc/, "xyz"); print }' test.txt
2. 字符串分割
使用 split 可以按指定分隔符拆分字符串:
awk '{ split($0, arr, ","); print arr[1], arr[2] }' data.csv
八、正则表达式匹配
awk 支持正则表达式,常用于日志分析。
例如,查找包含 error 的行:
awk '/error/ { print }' app.log
查找第 1 列以 user 开头的行:
awk '$1 ~ /^user/ { print }' data.txt
查找第 1 列不以 user 开头的行:
awk '$1 !~ /^user/ { print }' data.txt
常见符号:
| 符号 | 含义 |
|---|---|
^ |
匹配开头 |
$ |
匹配结尾 |
. |
匹配任意单个字符 |
* |
匹配前一个字符多次 |
+ |
匹配前一个字符一次或多次 |
? |
匹配前一个字符零次或一次 |
[] |
匹配字符集合 |
九、格式化输出
awk 可以使用 printf 进行格式化输出。
例如:
awk '{ printf "%-10s %5d\n", $1, $2 }' students.txt
说明:
%-10s:字符串左对齐,宽度为 10。%5d:数字宽度为 5。\n:换行。
格式化输出常用于生成整齐的报表。
十、处理 CSV 文件
处理简单 CSV 文件时,可以使用逗号作为分隔符:
awk -F, '{ print $1, $3 }' data.csv
例如 data.csv:
name,age,city
Tom,20,Beijing
Jerry,18,Shanghai
打印姓名和城市:
awk -F, 'NR > 1 { print $1, $3 }' data.csv
NR > 1 表示跳过表头。
十一、统计日志访问次数
假设日志格式如下:
192.168.1.1 - - [date] "GET /index.html HTTP/1.1" 200
192.168.1.2 - - [date] "GET /api HTTP/1.1" 200
192.168.1.1 - - [date] "GET /home HTTP/1.1" 404
统计每个 IP 出现次数:
awk '{ count[$1]++ } END { for (ip in count) print ip, count[ip] }' access.log
这里使用了数组 count:
count[$1]++
表示以 IP 地址作为数组下标进行计数。
如果想按访问次数排序,可以结合 sort:
awk '{ count[$1]++ } END { for (ip in count) print count[ip], ip }' access.log | sort -nr
十二、awk 常见命令示例
查看某列最大值:
awk 'BEGIN { max = 0 } { if ($2 > max) max = $2 } END { print max }' data.txt
统计文件总行数:
awk 'END { print NR }' file.txt
打印第 10 行:
awk 'NR == 10' file.txt
打印第 3 到第 8 行:
awk 'NR >= 3 && NR <= 8' file.txt
打印包含指定关键字的行号:
awk '/error/ { print NR, $0 }' app.log
十三、使用注意事项
-
字段分隔符要设置正确
如果文件使用逗号、冒号、Tab 分隔,需要提前用-F或FS设置。 -
注意引号使用
在 Shell 中,awk脚本通常使用单引号包裹,避免 Shell 解释特殊字符。 -
变量名不要和字段冲突
awk中的变量名应清晰,避免与$1、$2等字段混淆。 -
处理大数据时尽量只遍历一次
awk是流式处理工具,适合逐行读取,效率较高。 -
复杂逻辑可写成 awk 脚本文件
如果命令太长,可以保存为.awk文件,提高可维护性。
例如:
awk -f script.awk data.txt
script.awk 内容示例:
BEGIN { FS="," }
NR > 1 { print $1, $3 }
总结
awk 是 Linux 中非常实用的文本处理工具,核心特点是按行读取、按字段分析,并通过条件和动作完成过滤、计算、替换和统计。无论是处理日志、CSV 数据,还是生成报表,awk 都能用简洁的命令完成复杂任务。掌握 awk 的基本语法、字段变量、条件过滤、数组统计和格式化输出,就能大幅提升 Linux 命令行下的数据处理效率。