模式、范围与 BEGIN/END 块
使用条件模式筛选记录,并通过 BEGIN 和 END 块生成表头与汇总值。
模式、范围与 BEGIN/END 块 是 CoddyKit 上的免费 Linux Command Line & Bash Scripting Mastery 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Linux Command Line & Bash Scripting Mastery 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Linux Command Line & Bash Scripting Mastery 课程共包含 4 节课。
什么是 awk 模式?
在 awk 中,模式是一个条件,用于控制操作代码块是否针对给定的输入行执行。一般形式如下:
awk 'pattern { action }' file如果模式匹配当前记录,就会执行操作。如果没有指定操作,awk 默认会打印整行。模式可以是:
- 正则表达式 —
/regex/ - 关系表达式 —
$3 > 100 - 复合表达式 —
$1 == "ERROR" && $4 > 500 - 范围模式 —
/start/,/end/ - 特殊模式 —
BEGIN和END
理解模式,是将 awk 用作强大数据过滤器而不仅仅是列打印工具的关键。
使用正则表达式模式过滤行
最常见的模式类型是用正斜杠括起来的正则表达式。awk 会将每一行与正则表达式进行测试,并且只对匹配的行执行操作。
下面我们过滤一个类似 /var/log/syslog 的文件,只显示包含单词 ERROR 的行:
#!/usr/bin/env bash
# Simulate a log file and filter ERROR lines
log=$(cat <<'EOF'
2026-06-11 08:01:22 INFO service started
2026-06-11 08:02:05 ERROR disk quota exceeded on /dev/sda1
2026-06-11 08:02:44 WARN memory usage at 80%
2026-06-11 08:03:10 ERROR connection timeout to 10.0.0.5
2026-06-11 08:03:55 INFO backup completed
EOF
)
echo "=== ERROR lines only ==="
echo "$log" | awk '/ERROR/ { print NR": "$0 }'否定模式和复合模式
在正则表达式模式前加上 ! 可以将其取反,从而匹配不包含该模式的行。使用 &&(AND)或 ||(OR)组合多个条件,以实现精细控制。
!/DEBUG/— 跳过调试行$3 > 500 && $5 == "POST"— 较大的 POST 请求/WARN/ || /ERROR/— 两种严重级别中的任一种
下面的示例会解析一个简化的访问日志,只打印响应大小超过 1000 字节的 POST 请求:
#!/usr/bin/env bash
access=$(cat <<'EOF'
10.0.0.1 GET /api/ping 200 48
10.0.0.2 POST /api/upload 201 2048
10.0.0.3 GET /api/users 200 512
10.0.0.4 POST /api/data 200 3500
10.0.0.5 POST /api/health 200 60
EOF
)
echo "Large POST requests (>1000 bytes):"
echo "$access" | awk '$2 == "POST" && $5 > 1000 { print $1, $3, "size="$5 }'范围模式:/start/,/end/
范围模式选择一个连续的记录块——从匹配 /start/ 的行开始,到匹配 /end/ 的行结束,首尾两行都包括在内。语法如下:
awk '/start/,/end/ { action }' file请了解以下关键行为:
- 范围会在第一行匹配
/start/时激活,并在之后第一行匹配/end/后停用。 - 如果
/end/从未匹配,范围会一直保持激活状态,直到 EOF。 - 同一文件中多个互不重叠的范围会分别独立处理。
因此,范围模式非常适合从配置文件、带分隔标题的日志或多块报告中提取标记的部分。
使用范围模式提取部分内容
假设某个服务器配置包含多个以 [section] 标题分隔的命名部分。现在我们只需要 [database] 内的行:
#!/usr/bin/env bash
config=$(cat <<'EOF'
[server]
host = 0.0.0.0
port = 8080
[database]
host = 127.0.0.1
port = 5432
name = appdb
user = admin
[cache]
host = 127.0.0.1
port = 6379
EOF
)
echo "=== [database] section ==="
echo "$config" | awk '/\[database\]/,/^\[/' \
| awk 'NR > 1 && !/^\[/ && NF'BEGIN 代码块
BEGIN 代码块会在读取任何输入之前执行一次。它适用于:
- 打印报告标题
- 初始化变量和计数器
- 设置字段分隔符(
FS)或其他内置变量 - 运行不需要输入的独立
awk程序
语法:
awk 'BEGIN { setup } pattern { action }' file在 BEGIN 中设置 FS,是替代 -F 标志的简洁方式——尤其适用于编写多规则程序,因为分隔符逻辑可以放在脚本内部。
#!/usr/bin/env bash
csv=$(cat <<'EOF'
alice,engineering,95000
bob,marketing,72000
carol,engineering,105000
dave,hr,68000
EOF
)
echo "$csv" | awk 'BEGIN {
FS = ","
printf "%-10s %-15s %10s\n", "Name", "Department", "Salary"
print "--------------------------------------------"
}'END 代码块
END 代码块会在处理完最后一条记录后执行一次。它适合用于:
- 打印处理过程中累计的总计、平均值和摘要
- 刷新或关闭输出文件
- 为格式化报告打印页脚行
主规则中设置的变量在 END 中仍然处于作用域内,这正是实现累计总计的方式。下面的示例会对 CSV 中的薪资值求和,并在页脚打印总计:
#!/usr/bin/env bash
csv=$(cat <<'EOF'
alice,engineering,95000
bob,marketing,72000
carol,engineering,105000
dave,hr,68000
EOF
)
echo "$csv" | awk -F',' '
{ total += $3; count++ }
END { printf "Employees: %d Total payroll: $%d\n", count, total }
'组合使用 BEGIN、规则和 END
将三个代码块组合成一个独立完整的 awk 程序后,才能真正发挥它们的作用:该程序打印标题、处理每条记录并打印摘要。这种模式是基于 shell 的报告流水线的基础。
下面是一个完整的报告生成器,它读取包含 Web 请求的 CSV,打印每行的详细信息,并在最后统计响应时间超过 1 秒的请求数:
#!/usr/bin/env bash
data=$(cat <<'EOF'
/api/ping,0.03
/api/users,1.45
/api/login,0.88
/api/upload,2.10
/api/health,0.02
/api/report,1.73
EOF
)
echo "$data" | awk -F',' '
BEGIN {
printf "%-20s %10s %s\n", "Endpoint", "Latency(s)", "Status"
print "--------------------------------------"
}
{
status = ($2 > 1.0) ? "SLOW" : "OK"
if (status == "SLOW") slow++
printf "%-20s %10s %s\n", $1, $2, status
}
END {
print "--------------------------------------"
printf "Slow requests: %d / %d\n", slow, NR
}
'使用 BEGIN 设置 OFS 和 ORS
有两个经常被忽略的输出变量可以在 BEGIN 中简洁地设置:
- OFS(输出字段分隔符)——使用
$1=$1重建记录或使用print $1, $2时插入字段之间 - ORS(输出记录分隔符)——在每次
print调用后追加(默认值为\n)
设置 OFS=",",即可在一次处理中将 TSV 重新格式化为 CSV,而无需拼接字符串。将 ORS 改为 "\n---\n",即可自动在记录之间添加分隔线。
#!/usr/bin/env bash
# Convert whitespace-delimited data to CSV with a header
data=$(cat <<'EOF'
alice engineering 95000
bob marketing 72000
carol engineering 105000
EOF
)
echo "$data" | awk 'BEGIN { OFS=","; print "name,dept,salary" }
{ $1=$1; print }'实际范围模式:日志事件窗口
范围模式在运行日志分析中非常有用。一个常见任务是提取事件开始和结束之间的所有日志行,这些位置由 INCIDENT START 和 INCIDENT END 等标记消息标识。
在下面的示例中,awk 只提取事件窗口内的行,并统计其中的 ERROR 事件数量——将范围模式、累加器和 END 摘要结合在一起:
#!/usr/bin/env bash
log=$(cat <<'EOF'
08:00:01 INFO Normal operation
08:01:00 INFO INCIDENT START: disk pressure detected
08:01:05 ERROR write failed on /dev/sda1
08:01:09 ERROR inode table corruption
08:01:14 WARN remounting read-only
08:01:22 INFO INCIDENT END: disk replaced
08:02:00 INFO Normal operation resumed
EOF
)
echo "$log" | awk '
/INCIDENT START/,/INCIDENT END/ {
print
if (/ERROR/) errors++
}
END { print "Errors during incident:", errors+0 }
'在范围中跳过分隔行
默认情况下,范围模式会包含匹配 /start/ 和 /end/ 的行本身。若要跳过这些分隔行,只保留中间的内容,可以使用否定条件或标志变量保护操作:
- 否定方式:
/start/,/end/ { if (!/start/ && !/end/) print } - 标志方式: 在匹配
/start/时手动将变量设为 1,在匹配/end/时设为 0
当分隔文本也可能出现在正文内容中时,标志方式更加可靠:
#!/usr/bin/env bash
doc=$(cat <<'EOF'
## preamble
some intro text
## BEGIN_REPORT
row1: alpha 100
row2: beta 200
row3: gamma 150
## END_REPORT
## appendix
EOF
)
echo "$doc" | awk '
/## BEGIN_REPORT/ { capture=1; next }
/## END_REPORT/ { capture=0 }
capture { print }
'知识检查:BEGIN 代码块的行为
请测试您对 BEGIN 和 END 代码块如何与 awk 中的输入处理交互的理解。
课程回顾:模式、范围和 BEGIN/END
在本课中,您掌握了 awk 程序中三个最强大的结构特性:
- 模式 — 正则表达式(
/ERROR/)、关系表达式($3 > 1000)、否定模式(!/DEBUG/)和复合模式(&&、||)可以控制哪些记录触发操作,而无需显式使用if语句。 - 范围模式(
/start/,/end/)— 选择连续的记录块,非常适合提取日志事件窗口、配置部分和报告片段。如果需要排除分隔行本身,请使用标志变量(next+ 布尔值)。 - BEGIN 代码块 — 在读取任何输入之前执行一次;适合设置
FS、OFS、ORS,初始化计数器以及打印报告标题。 - END 代码块 — 在处理完所有输入后执行一次;适合使用主规则中累计的变量打印总计、平均值和页脚。
这些特性结合起来,可以让您编写完整且自解释的 awk 程序:读取原始文本并输出结构化、易于人类阅读的报告——全部在单个流水线阶段完成,无需临时文件或外部工具。
常见问题解答
「模式、范围与 BEGIN/END 块」课时是免费的吗?
是的 — 「模式、范围与 BEGIN/END 块」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Linux Command Line & Bash Scripting Mastery 课程的其余内容,请升级到 CoddyKit PRO。 Linux Command Line & Bash Scripting Mastery 课程共包含 4 节课。
「模式、范围与 BEGIN/END 块」这节课中我会学到什么?
使用条件模式筛选记录,并通过 BEGIN 和 END 块生成表头与汇总值。 你通过在浏览器中直接运行的动手代码来练习 Linux Command Line & Bash Scripting Mastery,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Linux Command Line & Bash Scripting Mastery 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Linux Command Line & Bash Scripting Mastery 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「模式、范围与 BEGIN/END 块」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Linux Command Line & Bash Scripting Mastery 课中编写并运行代码吗?
能。每节 Linux Command Line & Bash Scripting Mastery 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- awk 中的记录、字段和自定义分隔符
- 模式、范围与 BEGIN/END 块
- 使用 awk 数组进行聚合与分组
- awk 函数、printf 格式化与报表生成