0Pricing
DevOps Bootcamp · 课时

模式、范围与 BEGIN/END 块

使用条件模式筛选记录,并通过 BEGIN 和 END 块生成表头与汇总值。

模式、范围与 BEGIN/END 块 是 CoddyKit 上的免费 DevOps Bootcamp 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 DevOps Bootcamp 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 DevOps Bootcamp 课程共包含 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 导师)并解锁 DevOps Bootcamp 课程的其余内容,请升级到 CoddyKit PRO。 DevOps Bootcamp 课程共包含 4 节课。

「模式、范围与 BEGIN/END 块」这节课中我会学到什么?

使用条件模式筛选记录,并通过 BEGIN 和 END 块生成表头与汇总值。 你通过在浏览器中直接运行的动手代码来练习 DevOps Bootcamp,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 DevOps Bootcamp 需要有经验吗?

无需任何先前经验。CoddyKit 上的 DevOps Bootcamp 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「模式、范围与 BEGIN/END 块」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 DevOps Bootcamp 课中编写并运行代码吗?

能。每节 DevOps Bootcamp 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. awk 中的记录、字段和自定义分隔符
  2. 模式、范围与 BEGIN/END 块
  3. 使用 awk 数组进行聚合与分组
  4. awk 函数、printf 格式化与报表生成
← 返回 DevOps Bootcamp