awk 命令用法解析

一、概述

awk 是一款强大的文本处理与数据分析工具,尤其擅长对结构化文本(如日志、表格数据)进行查询、统计、替换、分析等操作。其核心特点是:

  • 基于模式-动作对处理文本(匹配模式则执行动作)。
  • 按行处理文本,自动将每行拆分为“字段”(默认以空格/制表符分隔),方便按列操作。
  • 支持变量、函数、循环、判断等编程特性,可实现复杂逻辑。

二、基本语法

awk [参数] '模式 {动作}' [文件...]

核心参数

参数 作用
-F 分隔符 指定字段分隔符(默认:空格/制表符,支持正则,如 -F "[, :]+" 表示逗号、空格、冒号均为分隔符)
-v 变量=值 定义内置变量(处理前初始化)
-f 脚本文件 从文件中读取 awk 脚本(适用于复杂逻辑)

核心概念

  • 字段引用
    • $0:表示整行内容。
    • $n:表示第 n 列(如 $1 第一列,$3 第三列)。
    • $NF:表示最后一列(NF 是内置变量,存储当前行的字段总数)。
  • 模式:触发动作的条件,支持:
    • 行号(NR==3 表示第三行)。
    • 正则匹配(/reboot/ 表示包含 reboot 的行)。
    • 比较表达式($1~/^why/ 表示第一列以 why 开头)。
  • 动作:对匹配行执行的操作,常用 print(打印)、gsub(替换)、变量运算等,需用 {} 包裹。

三、核心功能与示例

1. 基础查询(按行/列筛选)

(1)按行号查询

通过内置变量 NR(行号)指定目标行:

# 打印第1行和第3行
last | awk 'NR==1; NR==3'

# 打印1-3行
last | awk 'NR==1, NR==3'

(2)按内容匹配查询

通过正则表达式匹配包含特定内容的行:

# 打印包含"reboot"或"tty2"的行
last | awk '/reboot/; /tty2/'

# 打印第一列以"why"开头的行
last | awk '$1~/^why/'

(3)打印指定列

通过 $n 引用列,实现按列提取数据:

# 打印第1列和第3列(默认空格分隔列)
last | awk '/reboot/ {print $1, $3}'

# 打印最后一列($NF)
last | awk '/reboot/ {print $NF}'

# 自定义分隔符(以点分隔),打印IP地址的最后一段(第4列)
echo "192.168.0.102" | awk -F "." '{print $4}'  # 输出:102

2. 文本替换

使用 gsub(原内容, 新内容, 列) 函数替换指定列的内容(支持正则),gsub 就是 gawk substitute

# 将第三列中的点(.)替换为冒号(:)
last | awk '$1~/^why/ {gsub(/\./, ":", $3); print $3}'
# 示例输出:192:168:0:101

3. 数据统计与计算

(1)求和

通过变量累加实现数值求和:

# 计算1到10的总和(逐行打印累加结果)
seq 1 10 | awk '{sum = sum + $1; print sum}'
# 输出:
# 1
# 3(1+2)
# 6(1+2+3)
# ...
# 55(1到10总和)

(2)过滤与清洗

排除空行和注释行(以 # 开头):

# 过滤test03中既非空行也非注释行的内容
cat test03 | awk '!/^#|^$/'  # !表示取反,^#表示以#开头,^$表示空行

4. 特殊模式(BEGIN/END)

  • BEGIN:处理文本前执行(常用于设置表头、初始化变量)。
  • END:处理文本后执行(常用于汇总结果)。
# 打印表头,再输出last.txt的前3列(用column -t格式化对齐)
awk 'BEGIN{print "用户", "终端", "IP地址"}{print $1, $2, $3}' last.txt | column -t

# 统计文件总行数(END中打印NR的最终值)
cat test.txt | awk 'END{print "总行数:", NR}'

5. 多分隔符与复杂匹配

通过 -F 指定正则分隔符,处理多种分隔符混合的文本:

# 以制表符(\t)、空格、点(.)为分隔符,提取第6列
last.txt | awk -F "[\t .]+" '/why/ {print $6}'

四、常用示例汇总

需求 命令
打印文件第5行 awk 'NR==5' file.txt
打印所有行的第2列 awk '{print $2}' file.txt
以逗号分隔,打印第3列 awk -F "," '{print $3}' data.csv
统计包含"error"的行数 awk '/error/ {count++} END{print count}' log.txt
计算某列的平均值 awk '{sum+=$3; count++} END{print sum/count}' data.txt

五、注意事项

  1. 分隔符处理:连续空格会被视为单个分隔符(默认行为),需精确控制时用 -F 显式指定。
  2. 变量作用域BEGIN 中定义的变量可在整个处理过程中使用,NR(行号)、NF(字段数)为内置变量,自动更新。
  3. 正则转义:替换时特殊字符(如 .*)需用 \ 转义(如 gsub(/\./, "-", $1))。
  4. 输出格式化print 中用逗号分隔字段会自动添加空格,用 printf 可自定义格式(如 printf "%.2f\n", $3)。

六、扩展:gawk

1. 定义与核心定位

gawk(GNU AWK)是 GNU 项目对 AWK 语言的实现,是 AWK 标准的超集。在绝大多数 Linux 系统中,awk 命令通常是 gawk 的符号链接(即 awk 实际调用的是 gawk)。

gawk 继承了传统 AWK 的所有功能(如按行/列处理文本、模式-动作机制),并扩展了更多特性(如增强的正则支持、更多内置函数、数组优化等),是处理结构化文本、日志分析、数据统计的强大工具。

2. 与传统 AWK 的核心差异

gawk 在兼容标准 AWK 的基础上,增加了多项实用扩展,主要差异如下:

特性 传统 AWK gawk(GNU AWK)
正则支持 基础正则(BRE)为主 支持扩展正则(ERE)及更多元字符(如 \y 单词边界)
内置函数 基础字符串、数值函数 新增大量函数(时间处理、数组排序、高级字符串操作等)
数组功能 仅支持一维关联数组 支持多维数组(模拟)、数组排序(asort/asorti
扩展语法 无特殊扩展 支持自定义函数、命名引用、BEGINFILE/ENDFILE 模式等
兼容性 严格遵循原始 AWK 标准 可通过 --posix 选项兼容 POSIX 标准,默认支持更多扩展

3. 核心扩展特性与示例

(1)增强的正则表达式支持

gawk 除支持标准 AWK 的正则语法外,还支持 GNU 扩展正则元字符,例如:

  • \y:匹配单词边界(如 \yword\y 匹配完整单词 word)。
  • \B:非单词边界。
  • (?i):忽略大小写(仅在 --re-interval 选项开启时生效)。
# 匹配包含完整单词"boot"的行(不匹配"reboot"中的"boot")
gawk '/\yboot\y/' last.txt

(2)高级字符串处理函数

gawk 提供了比传统 AWK 更丰富的字符串函数,例如:

  • gensub(re, replacement, flags, target):支持捕获组引用(比 gsub 更灵活)。
  • substr(s, i, n):提取子串(从位置 i 开始,长度 n)。
  • split(s, arr, sep):将字符串按分隔符拆分到数组。
# 使用 gensub 提取 IP 地址中的前两段(如"192.168")
echo "192.168.0.102" | gawk '{print gensub(/([0-9]+\.[0-9]+)\..+/, "\\1", "g", $0)}'
# 输出:192.168

(3)数组增强功能

gawk 对数组的支持更强大,包括:

  • 多维数组(通过 arr[i,j] 语法模拟,实际存储为 i SUBSEP j)。
  • 数组排序:asort(arr) 按值排序,asorti(arr) 按键排序。
# 统计单词出现次数并按次数排序
echo "apple banana apple orange banana apple" | gawk '{
    for(i=1;i<=NF;i++) count[$i]++  # 计数
}
END{
    asorti(count, sorted)  # 按单词(键)排序
    for(i in sorted) print sorted[i], count[sorted[i]]
}'
# 输出:
# apple 3
# banana 2
# orange 1

(4)时间处理函数

gawk 提供了专门的时间处理函数,方便日志中的时间转换与计算:

  • mktime("YYYY MM DD HH MM SS"):将时间字符串转为时间戳(秒数)。
  • strftime(format, timestamp):将时间戳转为指定格式的字符串。
# 将当前时间戳转为"年-月-日 时:分:秒"格式
gawk 'BEGIN{
    ts = mktime("2023 11 16 18 30 00")  # 时间戳
    print strftime("%Y-%m-%d %H:%M:%S", ts)
}'
# 输出:2023-11-16 18:30:00

(5)自定义函数

gawk 支持用户自定义函数,可封装复杂逻辑,提高脚本复用性:

# 自定义函数计算平方和,并用其处理数据
gawk '
function sum_of_squares(a, b) {  # 定义函数
    return a*a + b*b
}
{
    print "平方和:" sum_of_squares($1, $2)  # 调用函数
}' data.txt
# 若 data.txt 内容为 "3 4\n5 12",输出:
# 平方和:25(3²+4²)
# 平方和:169(5²+12²)

(6)特殊模式:BEGINFILE/ENDFILE

gawk 新增 BEGINFILE(处理文件前执行)和 ENDFILE(处理文件后执行)模式,方便多文件处理时的初始化与收尾操作:

# 处理多个文件时,打印文件名及非空行数
gawk '
BEGINFILE {
    print "=== 处理文件:" FILENAME " ==="  # 文件名变量 FILENAME
    count = 0  # 初始化计数器
}
NF > 0 { count++ }  # 统计非空行
ENDFILE {
    print "非空行数:" count "\n"
}
' file1.txt file2.txt

4. 常用参数

gawk 继承了 awk 的所有参数(如 -F 指定分隔符、-v 定义变量、-f 执行脚本文件),并新增部分扩展参数:

参数 作用
--posix 启用 POSIX 兼容模式(禁用 GNU 扩展)
--re-interval 支持正则中的区间表达式(如 {n,m}
-W warning 显示警告信息(如未使用的变量)
-v VAR=VALUE 定义全局变量(与标准 awk 一致)