【shell编程知识点汇总】第九章 HTML 清洗、多行合并与条件替换

目录

[一、HTML 标签清洗:剥离尖括号内容](#一、HTML 标签清洗:剥离尖括号内容)

[二、多行合并:N 命令与换行符替换](#二、多行合并:N 命令与换行符替换)

[三、逻辑取反:! 的否定语义](#三、逻辑取反:! 的否定语义)

[四、匹配整体引用:& 的替身魔法](#四、匹配整体引用:& 的替身魔法)

五、精准定位:只输出最后一行

六、地址限定替换:条件化编辑

总结速查表

结语


在文本处理中,sed 不仅是简单的查找替换工具,更是能够处理结构化文本、执行条件逻辑的行级编辑器。本文针对六个高阶场景------从 HTML 标签清洗到地址限定替换------深入解析其内部机制,帮助你日志分析、数据清洗和配置管理。


一、HTML 标签清洗:剥离尖括号内容

问题: sed 's/<[^>]*>//g' 这个正则模式主要用来去除什么?

解析:

这是 sed 中经典的 HTML/XML 标签去除 模式,用于将文本中的所有 HTML 标签剥离,仅保留纯文本内容。

正则拆解:

模式 含义
< 匹配左尖括号(标签起始)
[^>]* 匹配从当前位置开始,一直到第一个 > 之前的所有内容 (不含 > 本身)。
> 匹配右尖括号(标签结束)
// 替换为空(删除)
g 全局标志,处理行内所有标签

工作原理:

[^>]* 是一个否定字符类 ,它贪婪地匹配标签内的所有属性、样式和文本,直到遇到第一个 > 为止。配合 g 标志,一行内出现的多个标签都会被依次移除。

示例:

复制代码
echo '<p class="intro">Hello <b>World</b>!</p>' | sed 's/<[^>]*>//g'
# 输出:Hello World!
#这里 s/<[^>]*>//g:把所有 HTML 标签替换成空字符串
#HTML 标签比如:<p>、<p class="intro">、<b>、</b>、</p> 全都能匹配到。

⚠️ 注意事项:

此模式适用于简单、格式规范 的 HTML。对于嵌套复杂、包含 > 在属性值中(如 data-val="a>b")或跨行标签的情况,sed 的单行处理能力可能力不从心,此时建议使用专门的 HTML 解析器。


二、多行合并:N 命令与换行符替换

问题: sed 'N; s/\n/ /' 其中的 N 命令和 \n 的替换实现了什么样的行操作?

解析:

该命令实现了将相邻的两行合并为一行 ,并用空格替代原有的换行符。

核心机制:

  • N(Next) :将输入流的下一行 追加到当前模式空间(pattern space),两行之间以换行符 \n 分隔

  • s/\n/ /:将模式空间中的换行符替换为空格,完成行合并

执行流程示例:

复制代码
# 输入:
# Hello
# World

sed 'N; s/\n/ /' file.txt
# 输出:
# Hello World

进阶理解:

N 是 sed 处理多行模式空间 的关键命令。默认情况下 sed 逐行处理,但 N 允许你将多行加载到同一个模式空间进行跨行操作。类似的命令还有:

  • P:打印模式空间中第一行(到第一个 \n 为止)

  • D:删除模式空间中第一行,并重新开始循环

循环合并多行:

如果需要将所有行合并为一行,可以配合标签实现循环:

复制代码
sed ':a; N; s/\n/ /; ta' file.txt
#:a定义一个标签 a(相当于循环的起点)。

三、逻辑取反:! 的否定语义

问题: sed '/foo/!d' file.txt 中的感叹号 ! 表示什么逻辑?

解析:

! 表示逻辑取反(negation),即"对不匹配地址的行执行后续命令"。

完整解读:

  • /foo/:地址条件,匹配包含字符串 foo 的行

  • !:否定该地址条件

  • d:删除命令

因此,/foo/!d 的含义是:删除所有不包含 foo 的行 ,最终只保留包含 foo 的行。

等价命令:

复制代码
sed '/foo/!d' file.txt
# 完全等价于:
sed -n '/foo/p' file.txt
#默认 sed 会输出所有行
#加 -n = 只输出我们指定的行
#p        print = 打印匹配到的行

! 的通用性:

! 可以应用于任何命令和地址组合,例如:

复制代码
sed '5!s/foo/bar/'   # 除第5行外,其他行中的 foo 替换为 bar
sed '$!d'            # 删除除最后一行外的所有行(仅保留最后一行)
#$ :匹配最后一行     ! :取反,不是最后一行      d :delete,删除当前行

四、匹配整体引用:& 的替身魔法

问题: 解释 sed 's/./& /g' 中符号 & 代表什么内容?

解析:

& 在 sed 的替换字符串中表示整个正则表达式匹配到的完整文本(即匹配模式的"镜像")。

命令拆解:

  • .:匹配任意单个字符(包括空格、标点等)

  • & :在替换部分,& 被替换为刚才匹配到的那个字符,后面再加一个空格

  • g:全局执行,对每行中每个字符都操作

效果演示:

复制代码
echo "Hello" | sed 's/./& /g'
# 输出:H e l l o 

& 的典型应用场景:

  1. 给匹配内容加标记

    echo "price: 100" | sed 's/[0-9]+/[&]/'

    把文本里的第一个数字用方括号 [] 包起来。

    +:匹配一个或多个(+ 在 sed 里需要转义写成 +)

    &:引用匹配到的内容

    输出:price: [100]

  2. 重复匹配内容

    echo "abc" | sed 's/.*/& &/'

    输出:abc abc

    .*:正则,匹配整行所有字符

  3. 与反向引用的区别

  • &:引用整个匹配串

  • \1, \2...:引用捕获组(括号内的部分)


五、精准定位:只输出最后一行

问题: sed -n '$p' file.txt 只会输出文件的哪一部分?

解析:

该命令仅输出文件的最后一行

符号解析:

符号 含义
-n 静默模式,抑制默认的逐行打印行为
$ 特殊地址,代表最后一行(Last Line)
p 显式打印命令

工作流程:

sed 逐行读取文件,-n 确保不自动输出任何内容。当读取到最后一行时,$ 地址匹配成功,触发 p 命令将其打印。

等效命令对比:

复制代码
sed -n '$p' file.txt        # sed 方式
tail -n 1 file.txt          # tail 方式
awk 'END{print}' file.txt   # awk 方式

扩展:倒数第 N 行

sed 本身没有直接支持倒数第 N 行的内置地址,但可以通过保持空间(hold space)或结合其他命令实现:

复制代码
# 输出倒数第3行
sed -n ':a; N; 4,$D; ba' file.txt
  • -n 安静模式,不自动输出任何行

  • :a 定义一个标签 a,循环的起点。

  • N 读取下一行,追加到模式空间(缓冲区)。

  • 4,$D

    • 4,$:从第 4 行最后一行
    • D:删除模式空间第一行
    • 意思:只要缓冲区里 ≥4 行,就删掉最旧的那一行
  • ba 无条件跳回标签 a,继续循环。

  • 读第 1 行 → 缓存:[1]

  • 读第 2 行 → 缓存:[1,2]

  • 读第 3 行 → 缓存:[1,2,3]

  • 读第 4 行 → 缓存≥4 行 → 删第 1 行 → 缓存:[2,3,4]

  • 读第 5 行 → 缓存≥4 行 → 删第 2 行 → 缓存:[3,4,5]

  • ... 一直到文件结束

  • 最后缓存里剩下的就是 最后 3 行


六、地址限定替换:条件化编辑

问题:sed '/Error/s/False/True/' 中,替换操作 s 是在所有行执行,还是受限于前面的地址?

解析:

替换操作受限于前面的地址 ,只有匹配 /Error/ 的行才会执行 s/False/True/

地址-命令结构:

sed 的命令格式为 [address[,address]]command。当命令前带有地址时,该命令仅对地址匹配的行生效。

执行逻辑:

  1. sed 逐行读取输入

  2. 检查当前行是否包含字符串 Error

  3. 如果包含 :执行 s/False/True/(将该行中的 False 替换为 True

  4. 如果不包含 :跳过 s 命令,该行原样输出(除非有其他命令)

示例演示:

复制代码
# 输入:
# Status: OK, Result: False
# Status: Error, Result: False
# Status: Warning, Result: False

sed '/Error/s/False/True/' file.txt
# 输出:
# Status: OK, Result: False
# Status: Error, Result: True
# Status: Warning, Result: False

复合地址应用:

地址限定可以与范围、正则、行号灵活组合:

复制代码
sed '5,10s/foo/bar/'       # 仅第5到10行执行替换
sed '/BEGIN/,/END/s/x/y/'  # 仅BEGIN到END范围内的行执行替换
sed '/^#/!s/^/  /'         # 对非注释行缩进两个空格
# /^#/:匹配以 # 开头的注释行
# !:取反 → 不是注释行
# s/^/ /:行首插入两个空格

总结速查表

问题 核心知识点 一句话总结
1 s/<[^>]*>//g 删除 HTML/XML 标签,提取纯文本
2 N; s/\n/ / 加载下一行到模式空间,将换行转为空格合并行
3 /foo/!d ! 取反,只保留匹配行,删除其余行
4 s/./& /g & 代表完整匹配串,给每个字符后加空格
5 -n '$p' -n 配合 $p,精确输出文件最后一行
6 /Error/s/.../ 地址限定命令作用域,仅匹配行执行替换

结语

sed 的魅力在于其地址-命令模型的简洁与强大。通过地址筛选目标行,再通过命令执行精确编辑,这种"先定位、后操作"的范式,使得 sed 在处理日志过滤、配置修改、数据格式化等任务时极为高效。

相关推荐
噢,我明白了2 小时前
表单的完整 CRUD 练习【极简个人记账本】(含前端后端链接mySQL)
java·前端·数据库·mysql
幽络源小助理2 小时前
MacCMSPro版视频影视系统源码_全开源高可用视频平台解决方案
前端·php·php源码
不会敲代码19 小时前
手写 Zustand:三十分钟带你搞懂状态管理库的核心原理
前端·javascript·源码
神奇的程序员9 小时前
重构了自己5年前写的截图插件
前端·javascript·架构
UXbot10 小时前
一人独立交付 UI + 前端:AI 驱动 UI 设计工具的五大功能模块深度评测
前端·低代码·ui·设计模式·交互
kobesdu10 小时前
【ROS2实战笔记-19】ROS2 生命周期节点的启动顺序、状态转换陷阱与热备方案
java·前端·笔记·机器人·ros·ros2
诚实可靠王大锤10 小时前
React Native 输入框与按钮焦点冲突解决方案(rn版本0.70.3)
前端·javascript·react native·react.js
kyriewen11 小时前
测试妹子让我写单测,我偷偷用AI一天干完一周的活
前端·chatgpt·cursor
2601_9577808411 小时前
Claude Code 2026年最新部署指南:从环境搭建到技能扩展
前端·人工智能·ai编程·claude