第41课 - awk 文本处理基础
学习目标
通过本课学习,你将能够:
- 理解
awk命令的基本语法和工作原理 - 使用
awk处理结构化文本文件中的字段 - 掌握
awk的核心内置变量和常用动作语句 - 运用
awk结合条件模式进行简单文本过滤与格式化输出
核心概念
1. 什么是 awk?
awk 是 Linux 系统中一个强大的文本和数据处理工具。你可以把它想象成一个针对文本文件的“编程语言”或“表格处理器”。它能按行读取输入,根据你指定的规则(模式)对每一行进行匹配,并执行相应的动作(如打印、计算)。它特别擅长处理结构化的文本数据,比如日志文件、CSV文件、/etc/passwd 等。
2. awk 的基本语法
awk 的基本结构非常清晰:
awk [选项] ‘模式 {动作}’ 输入文件
- 模式 (Pattern): 决定对哪些行执行动作。可以是正则表达式、条件判断(如
$3 > 100)或特殊模式(如BEGIN,END)。如果省略模式,则对每一行都执行动作。 - 动作 (Action): 由花括号
{}包裹的一系列命令,告诉awk对匹配的行做什么。最常用的动作是print。 - 输入文件:
awk要处理的文件。也可以通过管道接收来自其他命令的输入。
3. 字段与记录
awk 将输入文本视为记录 (Record) 和 字段 (Field)。
- 记录: 默认以换行符
\n分隔,所以一行就是一个记录。 - 字段: 默认以空格或制表符分隔。每个记录被分割成多个字段。
$0: 代表整个当前记录(即整行)。$1: 代表当前记录的第一个字段。$2: 代表第二个字段,以此类推。$NF: 代表最后一个字段(NF是一个内置变量,表示当前记录的字段总数)。
你可以通过 -F 选项自定义字段分隔符。
4. 内置变量
awk 提供了一些有用的内置变量,无需定义即可使用:
NR: 当前已读取的记录数(行号)。NF: 当前记录的字段总数。FS: 输入字段分隔符(默认空格)。OFS: 输出字段分隔符(默认空格)。
代码示例
示例1:基本字段提取
处理 /etc/passwd 文件,该文件以冒号 : 分隔。提取并打印用户名(第1列)和用户ID(第3列)。
# 使用 -F 指定输入分隔符为冒号
# 打印第一个字段($1)和第三个字段($3),并用自定义分隔符连接
awk -F: ‘{print $1, $3}’ /etc/passwd
预期输出(部分):
root 0
daemon 1
bin 2
...
示例2:添加表头和条件过滤
在上一个例子的基础上,添加表头,并只打印 UID 大于 1000 的普通用户。
# BEGIN 模式在读取任何输入前执行一次,这里用于打印表头
# 之后的模式 `$3 > 1000` 是一个条件,只有当第三个字段(UID)大于1000时,才执行后面的 print 动作
awk -F: ‘BEGIN {print “Username\tUserID”} $3 > 1000 {print $1, “\t”, $3}’ /etc/passwd
预期输出(部分):
Username UserID
ubuntu 1000
cloud 1001
示例3:使用内置变量和格式化输出
统计一个文件有多少行(记录),并打印每行的行号、字段数和内容。
# 创建一个测试文件
echo -e “Hello World\nThis is a test\nAwk is cool” > test.txt
# 使用 awk 处理
# NR 是行号,NF 是当前行的字段数,$0 是整行内容
# printf 用于格式化输出,类似C语言
awk ‘{printf “Line %d has %d fields: %s\n”, NR, NF, $0}’ test.txt
预期输出:
Line 1 has 2 fields: Hello World
Line 2 has 4 fields: This is a test
Line 3 has 3 fields: Awk is cool
实践练习
练习1:基础提取
要求:使用 awk 从 /etc/passwd 文件中提取并打印用户名和用户主目录(分别是第1列和第6列),用 - 连接。分隔符是冒号。
预期输出(开头几行):
root - /root
daemon - /usr/sbin
bin - /bin
练习2:条件过滤
要求:从 ls -l 命令的输出中,找出文件大小大于1000字节的文件,并只打印文件名(最后一列)和大小(第5列)。ls -l 的默认输出格式中,第5列是大小,最后一列是文件名。
提示:先使用 ls -l 查看输出格式,理解哪些列是你需要的。
预期输出示例(取决于你的目录内容):
some_large_file.log 2048
练习3:简单计算与格式化
要求:给定一个包含商品名称和价格的简单数据文件 prices.txt(你可以自己创建,例如包含三行:Apple 1.5、Banana 0.8、Orange 2.0)。使用 awk 计算所有商品价格的总和,并在处理完所有行后(使用 END 模式)打印出 “Total: [总和]”。
预期输出:
Total: 4.3
常见错误
- 忘记使用单引号:
awk的程序体(模式和动作)必须用单引号' '包裹,以防止 Shell 在将其传递给awk之前进行解释。例如,awk {print $1}是错误的,应为awk '{print $1}'。 - 字段分隔符使用错误:当数据分隔符不是空格时,忘记使用
-F选项指定。或者,在使用-F时,错误地将分隔符放在了动作语句里。 - 混淆字段变量:在动作语句中,错误地将
$用在了变量名前(如print $NR),而NR本身就是一个变量,不需要$。$0,$1...$NF是特殊的字段变量。 - 对
print和printf的混淆:print会自动在输出末尾添加换行符,并用输出字段分隔符(OFS,默认为空格)分隔参数。printf提供更精确的格式化控制,但需要手动添加换行符\n。
小结
本课我们学习了 awk 文本处理工具的基础知识:
- 核心结构:
awk的工作流程是模式 {动作}。模式决定对哪行操作,动作决定做什么。 - 字段处理:通过
$1,$2...$NF访问行内的不同字段,用-F指定分隔符。 - 内置变量:
NR(行号)、NF(字段数)等是自动化处理和统计的强大帮手。 - 模式应用:
BEGIN和END模式允许你在处理开始前和结束后执行动作,实现表头添加、汇总计算等功能。
awk 的功能远不止于此,它是 Shell 脚本中进行复杂文本处理和报告生成的利器。掌握这些基础后,我们将进入下一课,学习 awk 的高级用法,如数组、字符串函数和更多内置函数。现在,请务必完成练习,动手实践是掌握 awk 的最佳途径!