Skip to content

Commit 30aa5d1

Browse files
committed
docs: add awk-posix-compat skill from /vibeguard:learn
Extract cross-platform awk knowledge: BSD vs gawk regex differences, gsub character-level counting, func literal scope isolation.
1 parent 6c5b652 commit 30aa5d1

1 file changed

Lines changed: 141 additions & 0 deletions

File tree

skills/awk-posix-compat/SKILL.md

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
---
2+
name: awk-posix-compat
3+
description: |
4+
Shell 脚本中 awk 的 POSIX 兼容性指南。
5+
Use when: 编写或审查包含 awk 的 shell 脚本,
6+
尤其是需要 macOS + Linux 跨平台运行的场景。
7+
触发词: awk, BSD awk, POSIX regex, [[:space:]],
8+
guard 脚本, 跨平台 shell
9+
author: Claude Code
10+
version: 1.0.0
11+
date: 2026-04-03
12+
---
13+
14+
# awk POSIX 兼容性指南
15+
16+
## Problem
17+
18+
macOS 自带 BSD awk 严格遵循 POSIX 标准,不支持 GNU awk (gawk) 的正则扩展。
19+
在 Linux (gawk) 开发、macOS (BSD awk) 运行时**静默匹配失败** — 无报错但结果为空。
20+
21+
这类 bug 极难调试:脚本不报错,只是检测不到任何匹配,看起来像"没有问题"。
22+
23+
## Context / Trigger Conditions
24+
25+
- 编写包含 `awk '...'` 的 shell 脚本
26+
- 脚本需要在 macOS + Linux 上运行
27+
- 使用 awk 正则做代码模式检测(guard/linter/hook)
28+
- 错误现象:Linux 上能检测到问题,macOS 上检测为 0
29+
30+
## Solution
31+
32+
### 1. 正则替换规则(6 条)
33+
34+
| GNU awk 扩展 | POSIX 替代 | 说明 |
35+
|-------------|------------|------|
36+
| `\s` | `[[:space:]]` | 空白字符 |
37+
| `\S` | `[^[:space:]]` | 非空白字符 |
38+
| `\d` | `[0-9]` | 数字 |
39+
| `\w` | `[A-Za-z0-9_]` | 单词字符 |
40+
| `\b` | `[[:<:]]` / `[[:>:]]` | 词边界(BSD 语法) |
41+
| `\+` | `{1,}` 或重写模式 | 一次或多次 |
42+
43+
```bash
44+
# ❌ BAD — gawk 扩展,BSD awk 静默失败
45+
awk '/\s+defer\s/' "$file"
46+
47+
# ✅ GOOD — POSIX 兼容
48+
awk '/[[:space:]]+defer[[:space:]]/' "$file"
49+
```
50+
51+
### 2. 字符级计数(gsub 法则)
52+
53+
禁止行级正则匹配计数大括号:
54+
55+
```bash
56+
# ❌ BAD — 单行多个 { 时只计 1 次
57+
awk '/\{/ { depth++ }' "$file"
58+
59+
# ✅ GOOD — gsub 返回替换次数 = 精确字符数
60+
awk '{
61+
tmp = $0; opens = gsub(/\{/, "", tmp)
62+
tmp = $0; closes = gsub(/\}/, "", tmp)
63+
depth += opens - closes
64+
}' "$file"
65+
```
66+
67+
**原因**`/{/` 是行级匹配 — 一行有 `func() { if x {` 两个 `{`,行级只计 1 次,导致 depth 跟踪错误,后续作用域判断全部偏移。
68+
69+
### 3. 作用域隔离(嵌套结构检测)
70+
71+
检测"X 在 Y 内"的模式(如 `defer``for` 循环内)时,需要区分语法层级:
72+
73+
```bash
74+
# 需要 flit_depth 变量跟踪 func literal 嵌套
75+
# go func() { defer f.Close() }() 在 for 循环内是安全的
76+
# 因为 defer 绑定到 func literal 而非外层 for
77+
78+
if (is_func_literal && loop_depth > 0) {
79+
flit_depth++
80+
flit_base[flit_depth] = total_depth # 记录进入时的 brace 深度
81+
}
82+
83+
# defer 只在 loop_depth > 0 且 flit_depth == 0 时才报警
84+
```
85+
86+
## Verification
87+
88+
```bash
89+
# 1. 运行 portability check
90+
bash scripts/setup/check.sh
91+
# → "Guard Script Portability" 段应全绿
92+
93+
# 2. 手动扫描违规
94+
find guards/ -name '*.sh' -print0 \
95+
| xargs -0 grep -rnE '/[^/"]*\\[sdwb]' \
96+
| grep -vE '^\s*#|grep |sed '
97+
# → 期望输出为空(0 violations)
98+
```
99+
100+
## Example
101+
102+
**场景**`check_defer_in_loop.sh` 在 macOS 上检测不到任何 defer-in-loop 问题
103+
104+
**Before**(3 个 bug):
105+
```awk
106+
# Bug 1: \s 在 BSD awk 静默失败
107+
if (match(line, /^\s*for(\s|$)/))
108+
109+
# Bug 2: 行级计数漏计
110+
/\{/ { total_depth++ }
111+
112+
# Bug 3: go func(){defer} 误报
113+
if (match(line, /defer/) && loop_depth > 0) # 无 flit_depth 判断
114+
```
115+
116+
**After**(全部修复):
117+
```awk
118+
# Fix 1: POSIX 字符类
119+
if (match(line, /^[[:space:]]*for([[:space:]]|$)/))
120+
121+
# Fix 2: gsub 字符级计数
122+
tmp = line; opens = gsub(/\{/, "", tmp)
123+
tmp = line; closes = gsub(/\}/, "", tmp)
124+
total_depth += opens - closes
125+
126+
# Fix 3: func literal 作用域隔离
127+
if (match(line, /defer/) && loop_depth > 0 && flit_depth == 0)
128+
```
129+
130+
## Notes
131+
132+
- BSD awk 的 `\b` 词边界语法是 `[[:<:]]`(词首)和 `[[:>:]]`(词尾),与 gawk 的 `\b` 不同
133+
- `IGNORECASE = 1` 是 gawk 扩展,POSIX awk 不支持 — 用 `tolower()` 替代
134+
- macOS 上 `awk` 就是 BSD awk;即使安装了 `gawk`,脚本中写 `awk` 仍调用 BSD 版本
135+
- 自动检测已集成到 `scripts/setup/check.sh`"Guard Script Portability" 段)
136+
137+
## References
138+
139+
- 来源项目:vibeguard commit `6c5b652`(2026-04-02)
140+
- 涉及文件:`guards/go/check_defer_in_loop.sh``guards/rust/check_semantic_effect.sh`
141+
- POSIX 正则标准:IEEE Std 1003.1 (ERE)

0 commit comments

Comments
 (0)