sed删除a到b区间仅处理首个匹配块,不支持嵌套或多段;要删全部需awk维护flag或python正则,地址范围中^$需谨慎处理空格与特殊字符。

sed 删除从某字符开头到某字符结尾的整行区间(含边界)
直接用 sed -n '/^A/,/^B/p' 是打印,不是删除;要删掉这个区间,得用 d 命令,但注意:/^A/,/^B/d 会删掉从**第一行匹配 ^A 开始,到第一个后续匹配 ^B 的行(含这两行)**,之后就停止——它不支持多次匹配,也不跨段落处理嵌套。
常见错误是以为它能删所有 A–B 区间块,结果只删了第一个。
- 适用场景:日志里有明确起止标记的独立块,如
=== START ===和=== END ===各占一行 - 命令写法:
sed '/^=== START ===$/,/^=== END ===$/d' file.txt - 注意
$锚定行尾,避免误删=== START === EXTRA这类行 - 如果起止标记不在行首/行尾,去掉
^或$,但务必加转义,比如匹配[begin]要写成[begin]
sed 删除多行区间但保留起始行或结束行
默认 /A/,/B/d 是连头带尾一起删。如果只想删中间(A 和 B 行保留),就得拆开处理:
- 删 A 行之后、B 行之前的所有行(不含 A、B):
sed '/^A/{:a;n;/^B/!ba;d;}' file.txt - 更可读的替代方案是用 awk:
awk '/^A/{print; while (($0 = getline line) > 0 && !/^B$/) print line; if ($0 > 0) print line; next} 1' file.txt——但注意getline在 awk 里有陷阱,比如跳过下一行、影响 NR - 简单起见,若数据量不大,分两步:先用
sed '/^A/,/^B/{/^A/b; /^B/b; d;}'(用分支跳过 A/B,删其余)
遇到嵌套或不配对的 A/B 怎么办
sed 的地址范围是“贪婪且单次”的,不维护状态,也没计数器,所以面对 A…A…B…B 这种嵌套,它会把第一个 A 到第一个 B 当作一个区间,第二个 A 就被忽略了——根本不会进入第二次匹配。
- 典型现象:输入有 3 个
=== START ===,但只有第一个被处理,其余原样输出 - 此时必须换工具:用
awk维护一个 flag 变量,比如awk '/^=== START ===$/{flag=1; next} /^=== END ===$/{flag=0; next} !flag' file.txt - 如果起止模式复杂(如含变量、需正则捕获),Python 的
re.sub(r'(?s)START.*?END', '', text)更可靠,(?s)让.匹配换行符
性能与边界细节:空行、空格、大小写
实际文本往往不干净,sed 默认不忽略空白,所以 ^A 不会匹配 A(前面有空格)。
- 去前后空格再匹配:
sed '/^[[:space:]]*A[[:space:]]*$/,/^[[:space:]]*B[[:space:]]*$/d' - 大小写不敏感?sed 本身不支持
i标志用于地址范围(GNU sed 4.8+ 支持/A/I,/B/I,但旧系统不行),稳妥做法是先转小写:sed 's/.*/L&/; /^a$/,/^b$/d'(注意这会改写内容,仅适合纯匹配场景) - 空行干扰:如果 A 和 B 之间有空行,
/A/,/B/仍生效;但如果 A 是空行,得写成^$,不能留空
真正麻烦的是起止标记本身含特殊字符(比如 /*、^、$),这些必须逐个转义,漏一个就会语法错或逻辑错——建议先用 printf '%s
' 'pattern' | sed 's/[^^][$$.$*]/[\&]/g; s/^/\^/g; s/$/\$/g' 做简易转义预处理。











