Awk行范围模式匹配原理问询:单命令执行逻辑解析
拆解Awk提取指定范围文本的执行逻辑
先明确场景:我们有一个包含多个START-END区块的文本文件,需要提取其中包含Plantae的完整区块,对应的Awk命令及相关内容如下:
目标文件内容(file.txt)
START Name: Apple Kingdom: Plantae Family: Rosaceae END -------------------- START Name: Cat Kingdom: Animalia Family: Felidae END -------------------- START Name: Orange Kingdom: Plantae Family: Rutaceae END -------------------- START Name: Dog Kingdom: Animalia Family: Canidae END --------------------
执行命令
awk '/START/ {var=""} {var=var ? var ORS $0 : $0} /END/ {if(var~/Plantae/) print var}' file.txt
预期结果
START Name: Apple Kingdom: Plantae Family: Rosaceae END START Name: Orange Kingdom: Plantae Family: Rutaceae END
核心执行逻辑拆解
Awk的本质是逐行处理文本,每读入一行(记为$0),就依次检查所有的「模式-动作」对,匹配到就执行对应的动作。下面按行拆解第一个包含Plantae的区块的执行过程:
1. 处理第一行:START
- 匹配模式
/START/,执行动作{var=""}:把变量var清空(此时var是空字符串) - 接着执行第二个动作块
{var=var ? var ORS $0 : $0}:
三元表达式var ? ... : ...中,空字符串在Awk里属于「假」,所以取冒号后的值$0(当前行内容START),此时var = "START"
2. 处理第二行: Name: Apple
- 不匹配
/START/和/END/,直接执行第二个动作块:
此时var非空(属于「真」),取var ORS $0——ORS是Awk内置变量,默认是换行符\n,拼接后得到"START\n Name: Apple",赋值给var
3. 处理第三行: Kingdom: Plantae
- 直接执行第二个动作块:
var拼接换行符和当前行内容,更新为"START\n Name: Apple\n Kingdom: Plantae"
4. 处理第四行: Family: Rosaceae
- 重复拼接逻辑,
var更新为包含前三行+当前行的完整字符串
5. 处理第五行:END
- 先执行第二个动作块:
var拼接换行符和END,此时var已经是整个START-END区块的完整文本(含所有行和换行分隔符) - 接着匹配模式
/END/,执行动作{if(var~/Plantae/) print var}:检查var是否包含Plantae,符合条件则打印整个区块内容
针对疑问的解答
1. 为什么var最终包含整个范围?
因为每处理一行(包括START和END),都会执行var=var ? var ORS $0 : $0:
- 第一次遇到START时,
var被清空,随后赋值为START行内容 - 之后每一行(直到END),都会把当前行通过换行符拼接到
var末尾 - 到END行时,最后一次拼接完成,
var就完整保存了整个区块的所有内容(包括换行分隔的每一行)
2. 为什么ORS只是换行符、$0只显示END?
ORS是Awk的内置固定变量,默认值就是换行符,不会随处理过程变化,每次调用都是取这个固定值$0代表当前正在处理的行,每处理一行,$0就会替换为当前行内容。你测试时是在/END/的动作块里打印$0,此时正在处理的是END行,所以只会输出END,且每个符合条件的区块对应一次打印
内容的提问来源于stack exchange,提问作者Terucin
相关产品推荐
相关产品推荐

